Potenziali errori di passaggio di oggetti CRT attraverso i limiti DLLPotential Errors Passing CRT Objects Across DLL Boundaries

Quando si passano oggetti di runtime del linguaggio C (CRT) come handle di file, impostazioni locali e variabili di ambiente all'interno o all'esterno di una DLL (chiamate di funzione oltre i limiti della DLL) può verificarsi un comportamento imprevisto se la DLL, nonché i file chiamati nella DLL, utilizzano copie diverse delle librerie CRT.When you pass C Run-time (CRT) objects such as file handles, locales, and environment variables into or out of a DLL (function calls across the DLL boundary), unexpected behavior can occur if the DLL, as well as the files calling into the DLL, use different copies of the CRT libraries.

Un problema correlato può verificarsi quando viene allocata memoria (in modo esplicito con new o malloc oppure, in modo implicito, con strdup, strstreambuf::str e così via) e quindi viene passato un puntatore oltre i limiti della DLL da liberare.A related problem can occur when you allocate memory (either explicitly with new or malloc, or implicitly with strdup, strstreambuf::str, and so on) and then pass a pointer across a DLL boundary to be freed. Questo può comportare una violazione di accesso alla memoria o problemi della memoria heap se la DLL e gli utenti utilizzano copie diverse delle librerie CRT.This can cause a memory access violation or heap corruption if the DLL and its users use different copies of the CRT libraries.

Un altro sintomo di questo problema può essere un errore nella finestra di output durante il debug come:Another symptom of this problem can be an error in the output window during debugging such as:

HEAP[]: indirizzo non valido specificato a RtlValidateHeap(#,#)HEAP[]: Invalid Address specified to RtlValidateHeap(#,#)

CauseCauses

Ogni copia della libreria CRT ha uno stato separato e distinto, che viene mantenuto dall'app o dalla DLL nella memoria locale dei thread.Each copy of the CRT library has a separate and distinct state, kept in thread local storage by your app or DLL. Di conseguenza, gli oggetti CRT come gli handle di file, le variabili di ambiente e le impostazioni locali sono validi solo per la copia di CRT nell'app o nella DLL in cui questi oggetti vengono allocati o impostati.As such, CRT objects such as file handles, environment variables, and locales are only valid for the copy of the CRT in the app or DLL where these objects are allocated or set. Quando una DLL e i relativi client app usano copie diverse della libreria CRT, non è possibile passare questi oggetti CRT attraverso il limite di DLL e aspettarsi di prelevarli correttamente dall'altra parte.When a DLL and its app clients use different copies of the CRT library, you cannot pass these CRT objects across the DLL boundary and expect them to be picked up correctly on the other side. Questo vale soprattutto per le versioni di CRT precedenti Universal CRT in Visual Studio 2015 e versioni successive.This is particularly true of CRT versions before the Universal CRT in Visual Studio 2015 and later. È presente una libreria CRT specifica della versione per ogni versione di Visual Studio compilata con Visual C++ 2013 o versioni precedenti.There was a version-specific CRT library for every version of Visual Studio built with Visual C++ 2013 or earlier. I dettagli interni di implementazione di CRT, ad esempio le strutture dati e le convenzioni di denominazione, sono differenti per ogni versione.Internal implementation details of the CRT, for example, its data structures and naming conventions, were different in each version. Il collegamento dinamico di codice compilato per una versione di CRT a una versione diversa della DLL CRT non è mai stato supportato, ma talvolta funziona. Questo comportamento, tuttavia, si verifica più per caso che grazie alla progettazione.Dynamically linking code compiled for one version of the CRT to a different version of the CRT DLL has never been supported, though occasionally it would work, more by luck than by design.

Inoltre, poiché ogni copia della libreria CRT dispone di un proprio gestore dell'heap, allocando memoria in una libreria CRT e passando il puntatore oltre i limiti di una DLL da liberare da una copia diversa della libreria CRT è potenzialmente causa di problemi che si verificano nella memoria heap.Also, because each copy of the CRT library has its own heap manager, allocating memory in one CRT library and passing the pointer across a DLL boundary to be freed by a different copy of the CRT library is a potential cause for heap corruption. Se si progetta la DLL in modo che passi gli oggetti CRT oltre i limiti o che allochi memoria e aspetti che questa venga liberata all'esterno della DLL, si limitano i client app della DLL a usare la stessa copia della libreria CRT usata dalla DLL.If you design your DLL so that it passes CRT objects across the boundary or allocates memory and expects it to be freed outside the DLL, you restrict the app clients of the DLL to use the same copy of the CRT library as the DLL. La DLL e i relativi client usano in genere la stessa copia della libreria CRT solo se sono collegati al momento del caricamento alla stessa versione della DLL CRT.The DLL and its clients normally use the same copy of the CRT library only if both are linked at load time to the same version of the CRT DLL. Poiché la versione della DLL della libreria Universal CRT usata da Visual Studio 2015 e versioni successive il Windows 10 è ora un componente di Windows distribuito in modo centralizzato, ucrtbase.dll, tale componente è lo stesso per le app compilate con Visual Studio 2015 e versioni successive.Because the DLL version of the Universal CRT library used by Visual Studio 2015 and later on Windows 10 is now a centrally deployed Windows component, ucrtbase.dll, it is the same for apps built with Visual Studio 2015 and later versions. Tuttavia, anche quando il codice CRT è identico, non è possibile assegnare memoria allocata in un heap a un componente che usa un altro heap.However, even when the CRT code is identical, you can't hand off memory allocated in one heap to a component that uses a different heap.

EsempioExample

DescrizioneDescription

In questo esempio viene passato un handle di file oltre i limiti di una DLL.This example passes a file handle across a DLL boundary.

La DLL e il file .exe sono compilati con /MD, in modo che condividono una sola copia di CRT.The DLL and .exe file are built with /MD, so they share a single copy of the CRT.

Se si ricompila con /MT in modo che vengano utilizzate copie separate di CRT, l'esecuzione del test1Main.exe risultante genera una violazione di accesso.If you rebuild with /MT so that they use separate copies of the CRT, running the resulting test1Main.exe results in an access violation.

// 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 );  
}  
// 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  

EsempioExample

DescrizioneDescription

In questo esempio vengono passate le variabili di ambiente oltre i limiti di una DLL.This example passes environment variables across a DLL boundary.

// 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 );  
}  
// 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.  

Se la DLL e il file .exe sono compilati con /MD in modo che solo una copia di CRT venga utilizzata, il programma viene eseguito correttamente e produce l'output seguente:If both the DLL and .exe file are built with /MD so that only one copy of the CRT is used, the program runs successfully and produces the following output:

New MYLIB variable is: c:\mylib;c:\yourlib  

Vedere ancheSee Also

CRT Library Features (Funzionalità della libreria CRT)CRT Library Features