Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Koden kan ha fel när du skickar C Runtime-objekt (CRT), till exempel filhandtag, nationella inställningar och miljövariabler till eller från en DLL. Funktionsanrop över DLL-gränsen kan orsaka oväntat beteende om DLL och filer som anropar till DLL använder olika kopior av CRT-biblioteken.
Ett relaterat problem kan uppstå när du allokerar minne (antingen explicit med new eller malloc, eller implicit med strdup, strstreambuf::stroch så vidare) och sedan skickar en pekare över en DLL-gräns där den frigörs. Sådana pekare kan orsaka en minnesåtkomstöverträdelse, eller heap-korruption, om DLL och dess användare använder olika kopior av CRT-biblioteken.
Ett annat symptom på det här problemet är ett fel i utdatafönstret under felsökningen, till exempel HEAP[]: Invalid Address specified to RtlValidateHeap(#,#)
Orsaker
Varje kopia av CRT-biblioteket har ett separat och distinkt tillstånd som lagras i trådlokal lagring av din app eller DLL.
CRT-objekt som filhandtag, miljövariabler och nationella inställningar är endast giltiga för kopian av CRT i appen eller DLL-filen där dessa objekt allokerades eller angavs. När en DLL och dess klienter använder olika kopior av CRT-biblioteket kan du inte förvänta dig att dessa CRT-objekt ska användas korrekt när de skickas över DLL-gränsen.
Det gäller särskilt CRT-versioner före Universal CRT i Visual Studio 2015 och senare. Det fanns ett versionsspecifikt CRT-bibliotek för varje version av Visual Studio som skapats med Visual Studio 2013 eller tidigare. Intern implementeringsinformation för CRT, till exempel datastrukturer och namngivningskonventioner, var olika i varje version. Dynamisk länkning av kod som kompilerades för en version av CRT till en annan version av CRT DLL har aldrig stötts. Ibland skulle det fungera, men på grund av tur snarare än design.
Varje kopia av CRT-biblioteket har en egen heap-hanterare. Det kan orsaka korruption av heapen om du allokerar minne i ett CRT-bibliotek och skickar pekaren över en DLL-gräns så att den frigörs av en annan kopia av CRT-biblioteket. Om din DLL skickar CRT-objekt över DLL-gränsen, eller allokerar minne som frigörs utanför DLL-filen, måste DLL-klienterna använda samma kopia av CRT-biblioteket som DLL:en.
DLL och dess klienter använder normalt samma kopia av CRT-biblioteket endast om båda är länkade vid inläsning till samma version av CRT DLL. Eftersom DLL-versionen av Universal CRT-biblioteket som används av Visual Studio 2015 och senare nu är en centralt distribuerad Windows-komponent (ucrtbase.dll), är det samma sak för appar som skapats med Visual Studio 2015 och senare versioner. Men även om CRT-koden är identisk kan du inte ge minne som allokerats i en heap till en komponent som använder en annan heap.
Exempel: Skicka filhandtag över en DLL-gräns
Beskrivning
Det här exemplet skickar en filreferens över en DLL-gräns.
DLL- och .exe-filerna skapas med /MD, så att de delar en enda kopia av CRT.
Om du bygger om med /MT så att de använder separata kopior av CRT, kommer körningen av det resulterande test1Main.exe att resultera i en åtkomstöverträdelse.
DLL-källfil test1Dll.cpp:
// test1Dll.cpp
// compile with: cl /EHsc /W4 /MD /LD test1Dll.cpp
#include <stdio.h>
__declspec(dllexport) void writeFile(FILE *stream)
{
char s[] = "this is a string\n";
fprintf( stream, "%s", s );
fclose( stream );
}
Körbar källfil test1Main.cpp:
// test1Main.cpp
// compile with: cl /EHsc /W4 /MD test1Main.cpp 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" );
}
this is a string
Exempel: Skicka miljövariabler över DLL-gränsen
Beskrivning
Det här exemplet skickar miljövariabler över en DLL-gräns.
DLL-källfil test2Dll.cpp:
// test2Dll.cpp
// compile with: cl /EHsc /W4 /MT /LD test2Dll.cpp
#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örbar källfil test2Main.cpp:
// test2Main.cpp
// compile with: cl /EHsc /W4 /MT test2Main.cpp test2dll.lib
#include <stdlib.h>
#include <stdio.h>
void readEnv();
int main( void )
{
_putenv( "MYLIB=c:\\mylib;c:\\yourlib" );
readEnv();
}
MYLIB has not been set.
Om du skapar både DLL- och EXE-filerna med hjälp /MDav , så att endast en kopia av CRT används, körs programmet korrekt och genererar följande utdata:
New MYLIB variable is: c:\mylib;c:\yourlib
Se även
.lib