CORRECTIF : Fuite de mémoire dans le pilote Jet ODBC avec les données SQL_NUMERIC ou SQL_C_BINARY

Traductions disponibles Traductions disponibles
Numéro d'article: 273772 - Voir les produits auxquels s'applique cet article
Ancien nº de publication de cet article : F273772
Agrandir tout | Réduire tout

Sommaire

Symptômes

Lorsque vous appelez la fonction SQLBindParameter dans le pilote Jet ODBC, et que vous liez à un type de données SQL de SQL_NUMERIC ou que vous liez SQL_C_BINARY à SQL_WCHAR, une fuite de mémoire survient.

Si vous utilisez l'Analyseur de performances (PerfMon) pour visualiser le compteur Octets privés pour le processus, vous voyez une augmentation progressive mais constante de la mémoire, et la mémoire n'est pas libérée lorsque les instructions ou les connexions se terminent.

Cause

Des tampons sont utilisés au sein du pilote Jet ODBC pour aider à convertir les types de données des paramètres ODBC en types de données natifs pour le moteur de base de données Jet. Il est fait référence à ces tampons par le biais de pointeurs conservés sur le handle d'instruction, au sein des descripteurs de paramètre (IPD).

Normalement, le code vérifie si le pointeur fait déjà référence à un tampon de mémoire valide, puis utilise à nouveau le tampon, s'il existe. Toutefois, lorsque vous liez un type de données SQL_NUMERIC, ou lorsque vous liez SQL_C_BINARY à SQL_WCHAR, de la mémoire nouvelle est allouée et attribuée au pointeur sans vérification préalable, et la valeur précédente est écrasée.

Résolution

Ce problème a été résolu dans les derniers Service packs de Windows 2000 et MDAC 2.5.
  • Pour résoudre ce problème, procurez-vous le dernier Service Pack de Windows 2000. Pour plus d'informations, consultez l'article suivant dans la Base de connaissances Microsoft :
    F260910 Procédures d'obtention du dernier Service Pack de Windows 2000
  • Pour résoudre ce problème, procurez-vous le dernier Service pack de Microsoft Data Access Components 2.5. Pour plus d'informations, consultez l'article suivant dans la Base de connaissances Microsoft :
    293312 INFO : Obtention du dernier Service Pack de MDAC 2.5
La version anglaise de ce correctif doit disposer des attributs de fichier suivants ou de ceux d'une version ultérieure :
Date      Version     Taille          Nom de fichier
----------------------------------------------------
13.09.00  4.0.5708.0  270.608 octets  Odbcjt32.dll
14.09.00  1.10.101.0  295.696 octets  Q273772_W2K_SP2_x86_en.EXE
REMARQUE : Ce correctif requiert Microsoft Data Access Components (MDAC) 2.5 Service Pack 1 (SP1) ou une version ultérieure en raison des dépendances sur les autres fichiers introduits à l'aide de MDAC 2.5 SP1. Aucun correctif n'est disponible que vous pouvez appliquer directement à MDAC 2.5.

Pour installer ce correctif sur une plate-forme Microsoft Windows 2000, exécutez le lot d'installation du correctif (Q273772_W2K_SP2_x86_en.EXE). Bien que le correctif lui-même ne dépende pas de la plate-forme, le lot d'installation du correctif a été conçu pour s'exécuter uniquement sur les plates-formes Windows 2000, et ne s'exécutera pas sur les plates-formes Microsoft Windows NT 4.0, Microsoft Windows 95, ni Microsoft Windows 98. MDAC contient des fichiers système protégés que vous pouvez remplacer uniquement par un installateur de correctif signé numériquement sous Windows 2000. Le fichier de correctif indépendant est fourni également pour que vous puissiez copier ce fichier directement sur les plates-formes Windows NT 4.0, Windows 95 ou Windows 98.


SOLUTION



Il n'existe pas de solution à ce problème.

Statut

Microsoft a confirmé l'existence de ce problème dans les produits Microsoft répertoriés au début de cet article. Ce problème a été corrigé pour la première fois dans Microsoft Data Access Components 2.5 Service Pack 2 et dans Microsoft Windows 2000 Service Pack 2.

Plus d'informations

Si vous examinez de manière périodique la mémoire dédiée au processus au cours de l'exécution du processus, vous pouvez voir un nombre croissant de 0x100000 (1048576) allocations d'octets. Si l'exécution du processus se poursuit, un dépassement de mémoire peut avoir lieu, entraînant le blocage (pas de réponse) ou l'échec du processus.

Procédure à suivre pour reproduire ce comportement



  1. Copiez le code suivant dans une application de console Microsoft Visual C++, puis compilez le code. Notez que vous pouvez avoir à changer le nom de la source de données, ainsi que l'ID et le mot de passe d'utilisateur.
    #include <windows.h>
    #include <sql.h>
    #include <sqlext.h>
    #include <tchar.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    
    #define LEAK_NUMERIC 1		//Uiliser cela pour déterminer une fuite de données NUMERIC ou BINARY
    
    void HandleError(SQLHANDLE	hHandle, SQLSMALLINT hType, RETCODE RetCode)
    {
    	SQLSMALLINT	iRec = 0;
    	SQLINTEGER	iError;
    	TCHAR		szMessage[1000];
    	TCHAR		szState[SQL_SQLSTATE_SIZE];
    
    
    	if (RetCode == SQL_INVALID_HANDLE)
    	{
    		fprintf(stderr,"Handle non valide !\n");
    		return;
    	}
    
    	while (SQLGetDiagRec(hType,
    			 hHandle,
    			 ++iRec,
    			 (SQLCHAR *)szState,
    			 &iError,
    			 (SQLCHAR *)szMessage,
    			 (SQLSMALLINT)(sizeof(szMessage) / sizeof(TCHAR)),
    			 (SQLSMALLINT *)NULL) == SQL_SUCCESS)
    	{
    		fprintf(stderr,TEXT("[%5.5s] %s (%d)\n"),szState,szMessage,iError);
    	}
    
    }
    
    
    char* szConnStringIn = "Driver={Microsoft Access Driver (*.mdb)};DBQ=E:\\JetLeak\\TestDatabase.mdb";
    char* szDropTable = "DROP TABLE LeakTable";
    //char* szInsertStatement = "INSERT INTO LeakTable VALUES (?)";
    char* szSelectStatement = "SELECT * FROM LeakTable WHERE val1 = ?";
    const int nParamCount = 1; 
    
    #if LEAK_NUMERIC
    char* szCreateTable = "CREATE TABLE LeakTable (val1 long)";
    #else
    char* szCreateTable = "CREATE TABLE LeakTable (val1 varchar(10))";
    #endif
    
    
    
    void main(int argc, char* argv[])
    {
    	SQLHENV henv;
    	SQLHDBC hdbc;
    	SQLHSTMT hstmt;
    	SQLRETURN nstatus;
    
    	char szConnStringOut[1024];
    	SQLSMALLINT cbConnOut;
    	SQLINTEGER status[nParamCount];
    
    #if LEAK_NUMERIC
    	SQLCHAR szParam[nParamCount][10] = {"12345"};
    #else
    	BYTE szParam[nParamCount][10] = {0x31,0x33,0x34,0x39};
    #endif
        
    	//Pas de vérification des codes de renvoi dans certains cas par soucis de
            clarté.
    	
    	nstatus = SQLAllocHandle(SQL_HANDLE_ENV,NULL,&henv);
    	nstatus = SQLSetEnvAttr(henv,SQL_ATTR_ODBC_VERSION,(SQLPOINTER) 
    SQL_OV_ODBC3,0);
    	nstatus = SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);
    
    	nstatus = SQLDriverConnect(hdbc,
    			NULL,
    			(SQLCHAR*) szConnStringIn,
    			SQL_NTS,
    			(SQLCHAR*) szConnStringOut,
    			sizeof (szConnStringOut),
    			&cbConnOut,
    			SQL_DRIVER_COMPLETE);
    							
    	if (nstatus != SQL_SUCCESS && nstatus != SQL_SUCCESS_WITH_INFO)
    	{
    		HandleError(hdbc,SQL_HANDLE_DBC,nstatus);
    		return;
    	}
    	nstatus = SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt);	
    
    	nstatus = SQLExecDirect(hstmt, (SQLCHAR*) szDropTable, SQL_NTS);
    	nstatus = SQLExecDirect(hstmt, (SQLCHAR*) szCreateTable, SQL_NTS);
    
    	if (!SQL_SUCCEEDED(nstatus))
    	{
    		HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
    	}
    	int i;
    	//un seul paramètre dans ce cas
    	for (i=0; i < nParamCount; i++)
    	{
    		status[i] = SQL_NTS;
    
    
    
    #if LEAK_NUMERIC
    		nstatus = SQLBindParameter(hstmt,
    			i+1,
    			SQL_PARAM_INPUT,
    			SQL_C_CHAR,
    			SQL_NUMERIC, 
    			10, 
    			0,
    			szParam[i],
    			10,
    			&status[i]);
    #else
    
    		nstatus = SQLBindParameter(hstmt,
    			i+1,
    			SQL_PARAM_INPUT,
    			SQL_C_BINARY,
    				SQL_WCHAR,
    			10, 
    
    			0,
    			szParam[i],
    			10,
    			&status[i]);
    #endif
    	
    	
    	}
    
    	nstatus = SQLPrepare(hstmt,(SQLCHAR*) szSelectStatement, SQL_NTS);
    	if (nstatus != SQL_SUCCESS)
    	{
    		HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
    	}
    
    	for (i=0; i < 100000; i++)
    	{
    		if (i % 100 == 0)
    		{
    			printf("Heures %d sélectionnées\n", i);
    			//printf("Enregistrements %d insérés\n", i);
    			Sleep(100);
    		}
    		nstatus = SQLExecute(hstmt);
    		if (nstatus != SQL_SUCCESS)
    		{
    			HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
    		}
    		SQLFreeStmt(hstmt, SQL_CLOSE);
    	}
    	nstatus = SQLExecDirect(hstmt, (SQLCHAR*) "DELETE FROM LeakTable", 
    SQL_NTS);
    	if (nstatus != SQL_SUCCESS)
    	{
    		HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
    	}
    
    	SQLFreeStmt(hstmt, SQL_CLOSE);
    	SQLDisconnect(hdbc);
    
    }
    
    
    REMARQUE : Vous pouvez utiliser la constante LEAK_NUMERIC pour démontrer la fuite SQL_NUMERIC ou SQL_C_BINARY.
  2. Créez une nouvelle base de données Microsoft Access vide comme spécifié par l'emplacement dans votre chaîne de connexion.
  3. Commencez l'exécution du code, puis utilisez l'Analyseur de performances pour surveiller le compteur Octets privés pour le processus.

    Notez que le compteur Octets privés augmente de manière constante au fil de l'exécution du code.

Propriétés

Numéro d'article: 273772 - Dernière mise à jour: mercredi 18 février 2004 - Version: 4.0
Les informations contenues dans cet article s'appliquent au(x) produit(s) suivant(s):
  • Pilote ODBC pour Access 4.0 de Microsoft
  • Microsoft Data Access Components 2.5
  • Microsoft Data Access Components 2.5 Service Pack 1
Mots-clés : 
kbbug kbfix kbmdac250sp2fix kbwin2000presp2fix kbjet kbmdac250bug kbgrpdsvcdb kbgrpdsmdac kbmdac250sp1bug KB273772
L'INFORMATION CONTENUE DANS CE DOCUMENT EST FOURNIE PAR MICROSOFT SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE. L'UTILISATEUR ASSUME LE RISQUE DE L'UTILISATION DU CONTENU DE CE DOCUMENT. CE DOCUMENT NE PEUT ETRE REVENDU OU CEDE EN ECHANGE D'UN QUELCONQUE PROFIT.

Envoyer des commentaires

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com