Potenciální chyby procházející přes hranice DLL objektů CRT
Při předání C Runtime (CRT) objektů popisovačů souborů, národní prostředí a proměnné prostředí do DLL (volání funkce přes hranice DLL), nebo neočekávané chování může dojít, pokud kopie CRT knihoven DLL, soubory do knihovny DLL, volání.
Související problém může nastat, když přidělit paměť (buď výslovně s new nebo malloc, nebo implicitně s strdup, strstreambuf::str, a tak dále) a průchod přes hranice DLL na uvolnění ukazatele.Pokud kopie CRT knihoven DLL a jeho uživatelů může způsobit poškození přístup k paměti narušení nebo haldy.
Dalším příznakem tohoto problému může být chyba v okně Výstup během ladění, například:
[] HALDY: Neplatná adresa k RtlValidateHeap(#,#)
Příčiny
Každá kopie knihovny CRT má odděleného státu.Jako takové CRT objekty jako jsou popisovače souborů, proměnné prostředí a národní prostředí jsou platné pouze pro kopie CRT, kde tyto objekty jsou přiděleny nebo nastavit.Knihovnu DLL a jeho uživatelé používat různé kopie knihovny CRT, nelze předat tyto objekty CRT přes hranice DLL a je třeba správně nastupují na druhé straně.
Protože každá kopie CRT knihovny má svou vlastní správce hald, přidělování paměti v jedné knihovně CRT a ukazatel prochází přes hranice na uvolnění jinou kopii CRT knihovny DLL je také potenciální příčinu poškození haldy.
Při navrhování knihovny DLL tak, aby objekty CRT prochází přes hranice nebo přidělí paměť a očekává, že má být uvolněno mimo knihovnu DLL, omezit uživatelům knihovny DLL použít stejnou kopii knihovny CRT jako knihovny DLL.DLL a jeho uživatelé používat stejnou kopii knihovny CRT pouze v případě, že oba jsou propojeny se stejnou verzí knihovny DLL CRT.To může být problém, pokud zároveň aplikací vytvořených pomocí aplikace Visual C++ 5.0 s knihovny DLL, které jsou vytvořeny pomocí Visual C++ 4.1 nebo starší.Protože verze knihovny DLL CRT knihovny používané službou Visual C++ 4.1 je msvcrt40.dll a který používají vizuální 5.0 je msvcrt.dll, nelze sestavit aplikaci použít stejnou kopii knihovny CRT jako těchto knihoven DLL.
Je však výjimku.V americké angličtině verze a některé další lokalizované verze systému Windows 2000 jako dodané německé, francouzské a české verze předávání msvcrt40.dll (verze 4.20).Výsledkem je i když knihovna DLL je spojena s msvcrt40.dll a uživatel je spojen s msvcrt.dll, stále používáte stejnou kopii knihovny CRT protože všechna volání msvcrt40.dll jsou předány msvcrt.dll.
Tato verze serveru pro předávání msvcrt40.dll však není k dispozici v některých lokalizovaných verzích systému Windows 2000, například v japonštině, korejštině a čínština.Takže pokud aplikace cíle těchto operačních systémů, je nutné buď získat inovovanou verzi knihovny DLL, která nelze spoléhat na msvcrt40.dll nebo změnit aplikaci použít stejnou kopii knihovny CRT.Pokud vyvinuly knihovny DLL, to znamená opětovné sestavení s Visual C++ 4.2 nebo novější.Pokud je knihovna DLL výrobců, potřebujete dodavatele pro upgrade.
Poznámka: nelze přerozdělí tato verze knihovny DLL pro předávání msvcrt40.dll (verze 4.20).
Příklad
Description
V tomto příkladu předává popisovač souboru přes hranice knihovny DLL.
Soubor DLL a exe jsou tvořeny přepínače, takže sdílejí jednu kopii CRT.
Pokud znovu vytvoříte s /MT tak, že používají samostatné kopie CRT, spuštění výsledné test1Main.exe výsledky v narušení přístupu.
Kód
// test1Dll.cpp
// compile with: /MD /LD
#include <stdio.h>
__declspec(dllexport) void writeFile(FILE *stream)
{
char s[] = "this is a string\n";
fprintf( stream, "%s", s );
fclose( stream );
}
Kód
// test1Main.cpp
// compile with: /MD test1dll.lib
#include <stdio.h>
#include <process.h>
void writeFile(FILE *stream);
int main(void)
{
FILE * stream;
errno_t err = fopen_s( &stream, "fprintf.out", "w" );
writeFile(stream);
system( "type fprintf.out" );
}
Výsledek
this is a string
Příklad
Description
V tomto příkladu prochází přes hranice DLL proměnné prostředí.
Kód
// test2Dll.cpp
// compile with: /MT /LD
#include <stdio.h>
#include <stdlib.h>
__declspec(dllexport) void readEnv()
{
char *libvar;
size_t libvarsize;
/* Get the value of the MYLIB environment variable. */
_dupenv_s( &libvar, &libvarsize, "MYLIB" );
if( libvar != NULL )
printf( "New MYLIB variable is: %s\n", libvar);
else
printf( "MYLIB has not been set.\n");
free( libvar );
}
Kód
// test2Main.cpp
// compile with: /MT /link test2dll.lib
#include <stdlib.h>
#include <stdio.h>
void readEnv();
int main( void )
{
_putenv( "MYLIB=c:\\mylib;c:\\yourlib" );
readEnv();
}
Výsledek
MYLIB has not been set.
Pokud soubor DLL i exe jsou integrovány s přepínače tak, že se používá pouze jednu kopii CRT, program úspěšně spuštěn a následující výstup:
New MYLIB variable is: c:\mylib;c:\yourlib