Routines d’aide au débuggage pour la gestion de la mémoire vive en C

/******************************************************************************/
/* BP le 19/01/98                                                             */
/* Ensemble de routines pour aider au debuggage sur des allocations memoires  */
/* Fichier : GestMem.c                                                        */
/*                                                                            */
/*Copyright (C) 1998 Bruno Pean                                               */
/* EISTI Av du Parc, 950111 CERGY FRANCE                                      */
/*                                                                            */
/*This program is free software; you can redistribute it and/or modify        */
/*    it under the terms of the GNU General Public License as published by    */
/*    the Free Software Foundation; either version 2 of the License, or       */
/*    (at your option) any later version.                                     */
/*                                                                            */
/*    This program is distributed in the hope that it will be useful,         */
/*    but WITHOUT ANY WARRANTY; without even the implied warranty of          */
/*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           */
/*    GNU General Public License for more details.                            */
/*                                                                            */
/*    You should have received a copy of the GNU General Public License       */
/*    along with this program; if not, write to the Free Software             */
/*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               */
/*                                                                            */
/******************************************************************************/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define TSRC 30         /* Longueur maximale du nom d'un source     */
#define CTRL 0XABCD     /* Marqueur pour tester les ecrasements     */
                        /* Limiter a 30 car sous certains OS les    */
                        /* noms de fichiers peuvent etre plus long  */
                        
/************************************************************************/
/* Format des alloc gerees                                              */
/* CRTL:Source:LigneSource:LgUtil:DonneesUtil:CTRL:FILL                 */
/* CTRL : Marqueur                                                      */
/* Source :Nom du source de l'utilisateur                               */
/* LgUtil : Ligne du source de l'utilisateur                            */
/* Donnees : Donnees de l'utilisateur de longueur variable              */
/* CTRL : Marqueur                                                      */
/* FILL: Octet(s) vide pour limiter la casse si ecrasement              */
/*                le nombre d'octet est de TFILL_ALLOC_SECOURS          */
/*                Ce nombre est varibale cf GestMem.h                   */
/************************************************************************/
 

/*********************************************************/
/*                Types                                  */
/*********************************************************/
/* Liste pour memoriser les allocations */
typedef struct ListAlloc /* LLC des ALLOC */
        {
        char * Ptr; /* Ptr sur le malloc */
        struct ListAlloc * Suivant;
        } sListAlloc;

/*********************************************************/
/*                Fonctions                              */
/*********************************************************/

void * _MyMalloc(int n,char * Source, int Ligne,int TFill);
/************************************************************************/
/* But : allouer de la memoire                                          */
/* En entrees :        n: nombre  d'octets demandes par l'utilisateur   */
/*                Source : Nom du fichier source de l'appel             */
/*                Ligne : Ligne du source de l'appel                    */
/*                TFill : Nombre d'octets alloues en plus des octets    */
/*                        de l'utilisateur et des octets de controles   */
/* En sortie : un pointeur sur les octets alloues de l'utilisateur      */
/*                ou NULL si erreur                                     */
/* Visibilite : globale                                                 */
/* Remarques :        Doit normalement etre appelee via les defines ... */
/************************************************************************/
 
void * _MyRealloc(void * Ptr,int n,char * Source, int Ligne,int TFill, 
                        void (*AbortFct)(void));
/************************************************************************/
/* But : reallouer de la memoire                                        */
/* En entrees : Ptr : pointeur a reallouer                              */      
/*                n: nombre  d'octets demander par l'utilisateur        */
/*                Source : Nom du fichier source de l'appel             */
/*                Ligne : Ligne du source de l'appel                    */
/*                TFill : Nombre d'octets alloues en plus des octets    */
/*                        de l'utilisateur et des octets de controles   */
/*                AbortFct: Fonction  qui est appelee si un ecrasement  */
/*                        est detecte cf define ABORT_FCT               */
/* En sortie : un pointeur sur les octets alloues de l'utilisateur      */
/*                ou NULL si erreur                                     */
/* Visibilite : globale                                                 */
/* Remarques :        Doit normalement etre appelee via les defines ... */
/*                Avant de reallouer on appelle CheckPtr                */
/************************************************************************/

void * _MyCalloc(int a,int b,char * Source, int Ligne,int TFill);
/************************************************************************/
/* But : allouer de la memoire                                          */
/* En entrees : a :nombre de blocs a alloeur                            */
/*                b: nombre  d'octets pour chaque bloc                  */
/*                Source : Nom du fichier source de l'appel             */
/*                Ligne : Ligne du source de l'appel                    */
/*                TFill : Nombre d'octets alloues en plus des octets    */
/*                        de l'utilisateur et des octets de controles   */
/* En sortie : un pointeur sur les octets alloues de l'utilisateur      */
/*                ou NULL si erreur                                     */
/* Visibilite : globale                                                 */
/* Remarques :        Doit normalement etre appelee via les defines ... */
/************************************************************************/

void _MyFree( void * Ptr, char * Source, int Ligne, void (*AbortFct)(void));
/************************************************************************/
/* But : liberer de la memoire                                          */
/* En entrees : Ptr : le pointeur de l'utilisateur a liberer            */
/*                Source : Nom du fichier source de l'appel             */
/*                Ligne : Ligne du source de l'appel                    */
/*                AbortFct: Fonction  qui est appelee si un ecrasement  */
/*                        est detecte cf define ABORT_FCT               */
/* Visibilite : globale                                                 */
/* Remarques :        Doit normalement etre appelee via les defines ... */
/*                Avant de libere on appelle CheckPtr                   */
/************************************************************************/

void _TesterMemoire(char * Source,int Ligne, void (*AbortFct)(void));
/************************************************************************/
/* But : Verifier que tous les pointeurs alloués on ete liberes         */
/* En entrees : a :nombre de blocs a alloeur                            */ 
/*                b: nombre  d'octets pour chaque bloc                  */
/*                Source : Nom du fichier source de l'appel             */
/*                Ligne : Ligne du source de l'appel                    */
/* En sortie : un pointeur sur les octets alloues de l'utilisateur      */
/*                ou NULL si erreur                                     */
/* Visibilite : globale                                                 */
/* Remarques :        Doit normalement etre appelee via les defines ... */
/************************************************************************/

/*********************************************************/
/*                 Fonctions et Variable Internes        */
/*********************************************************/

static void AjouterLLC(char * Ptr);
/************************************************************************/
/* But : ajouter un pointeur a la liste des pointeurs alloues           */
/* En entrees : Ptr : le pointeur a ajouter                             */  
/* Visibilite : Locale                                                  */
/* Remarques :        Fontion de gestion interne                        */
/************************************************************************/

static SupprimerLLC(char* Ptr,char * Source,int Ligne,void (*AbortFct)(void));
/************************************************************************/
/* But : Supprimer un pointeur a la liste des pointeurs alloues         */
/* En entrees : Ptr : le pointeur a supprimer                           */
/* Visibilite : Locale                                                  */
/* Remarques :        Fontion de gestion interne                        */
/*                Avant de supprimer on appelle CheckPtr                */
/************************************************************************/

static void * CheckPtr(void * Ptr,char * Source, int Ligne, 
                                void (*AbortFct)(void));
/************************************************************************/
/* But : Verifier l'ecrasement d'un pointeur                            */
/* En entrees : Ptr : pointeur a reallouer                              */
/*                Source : Nom du fichier source de l'appel             */
/*                Ligne : Ligne du source de l'appel                    */
/*                AbortFct: Fonction  qui est appelee si un ecrasement  */
/*                        est detecte cf define ABORT_FCT               */
/* Visibilite : Locale                                                  */
/* Remarques :        Fontion de gestion interne                        */
/*                On verifie les marqueurs et si ecrasement on          */
/*                Affiche le nom du source et la ligne qui a fait appel*/
/*                a la fonction qui elle meme appel le check            */
/*                Si les marqueurs sont casses, on affiche un message   */
/*                puis on appelle la fonction AbortFct cf define        */
/*                        ABORT_FCT dans Gestmem.h                      */
/************************************************************************/

static sListAlloc Racine;
/************************************************************************/
/* Liste des allocs de l'utilisateurs                                   */
/************************************************************************/



/********************************************************/
/*                 Declartion des fonctions             */
/********************************************************/

void * _MyCalloc(int a,int b,char * Source, int Ligne,int TFill)
        {
        char * Tmp;
        Tmp = _MyMalloc(a*b ,Source, Ligne,TFill);
        memset(Tmp,0,a*b);
        return(Tmp);
        }

/********************************************************/
/********************************************************/
void * _MyRealloc(void * Ptr,int n,char * Source, int Ligne,int TFill, 
                        void (*AbortFct)(void))
        {
        char *  Tmp, * Retour, *Tampon;
        char * b;
        int * a;
	if (Ptr == NULL)
		return (_MyMalloc(n, Source, Ligne, TFill));

        Tmp = CheckPtr( Ptr,Source,Ligne,AbortFct);
        Tampon = Tmp;
        Tmp = (char*) realloc(Tmp,n /* les octets de l'utilisateur */+
                        sizeof(int) /* CTRL */+
                        TSRC +1 /* le source */+
                        sizeof(int)/* la ligne */ +
                        sizeof(int)/* le CTRL */ +
                        TFill
                        );
        SupprimerLLC(Tampon,Source,Ligne,AbortFct); /*Supprimer PTR de la LLC*/
        if (Tmp == NULL)
                return(NULL);
        a= (int *) Tmp;
        *a = CTRL;

        b = Tmp + sizeof(int); /* le CTRL */
        strncpy(b,Source,TSRC);
        b[TSRC] = '\0'; /* Si strlen(Source) > TSRC */

        a = (int*) (Tmp + sizeof(int) /* le CTRL */ +
                        TSRC +1 /* le Source */ 
                );
        *a =Ligne;


        a = (int*) (Tmp + sizeof(int) /* le CTRL */ +
                        TSRC +1 /* le Source */ +
                        sizeof(int) /* la ligne */ 
                );
        *a =n;

        a = (int*) (Tmp + sizeof(int) /* le CTRL */ +
                        TSRC +1 /* le Source */ +
                        sizeof(int) /* la ligne */ +
                        sizeof(int) /* la lg */ +
                        n /* les octets de l'utilisateurs */ 
                );
        *a= CTRL;

        AjouterLLC(Tmp);
        Retour = Tmp + sizeof(int) /* le CTRL */ +
                        TSRC +1 /* le Source */ +
                        sizeof(int) /* la ligne */+
                        sizeof(int) /* la lg util */;
        return((void*) Retour);
        }

/********************************************************/
/********************************************************/
void * _MyMalloc(int n,char * Source, int Ligne,int TFill)
        {
        char * Tmp;
        int * a;
        char * b;
        char * Retour;
        char Src[TSRC +1];
        Tmp = (char*) malloc(  sizeof(int)  /* CTRL */ +
                        TSRC+1 /* Le source */ +
                        sizeof(int) /* la ligne du SRC */ +
                        sizeof(int) /* la longueur de l'util */ +
                        n /* les octets de l'utilisateur */ +
                        sizeof(int) /* CTRL */ +
                        TFill /*octets si ecrasement ...*/
                        );
        if ( Tmp == NULL)
                return(Tmp);
        a=(int*) Tmp;
        *a=CTRL; /* Marqueur */
        strncpy(Src,Source,TSRC);
        Src[TSRC] = '\0' ;/*si nom du source trop grand ... */

        b= Tmp + sizeof (int); /* CTRL */
        strcpy(b,Src);

        a= (int*) ( Tmp + sizeof(int) /* CTRL*/+
                        TSRC +1 /* Le source */
                );
        *a=Ligne; /* Ligne du Source */

        a= (int*) ( Tmp + sizeof(int) /* CTRL*/+
                        TSRC +1 /* Le source */+
                        sizeof(int)
                );
        *a=n; /* Nb octets demander par l'utilisateur ... */

        a= (int*) ( Tmp + sizeof(int) /* CTRL*/+
                TSRC +1 /* Le source */ +
                +sizeof(int) /* Ligne du source */+
                sizeof(int) /* Longueur de l'utilisateur */+
                n /* les octets de l'utilisateurs */
                );

        *a = CTRL; /* Control de fin */


        AjouterLLC(Tmp); /* Ajout dans la LLC des PTR */
        Retour = Tmp + sizeof(int) /* CTRL */ +
                        TSRC +1 /* Le nom du source */ +
                        sizeof(int) /* La ligne du source */ +
                        sizeof(int); /* La longueur de l'utilisateur */

        return((void*)Retour);
        }


/********************************************************/
/********************************************************/
void _MyFree( void * Ptr, char * Source, int Ligne, void (*AbortFct)(void))
        {
        void * Tmp;
        Tmp = CheckPtr( Ptr,Source,Ligne,AbortFct);
        SupprimerLLC(Tmp,Source,Ligne,AbortFct); /* Supprimer PTR de la LLC */
        free(Tmp);
        }

/********************************************************/
/********************************************************/
static void * CheckPtr(void * Ptr,char * Source, int Ligne, 
                        void (*AbortFct)(void))
        {
        int Lg;
        char *SrcAlloc;
        int LigneAlloc;
        int *a;
        char * Tmp;
        int b;


        b=        sizeof(int) + /* LgUtil */ +
                sizeof(int) /*LigneSource */ +
                TSRC + 1 /* Le nom du source */ +
                sizeof(int) /* CTRL */;

        Tmp =(char*) Ptr;
        Tmp = Tmp - b;

        
        /* On recupere le premier CTRL  */
        a=(int *) Tmp;
        if ( *a != CTRL) /* Validite des infos ? */
                {
                fprintf(stderr,"\nErreur Fatale dans %s a la ligne %d\n",
                                Source,Ligne);
                fprintf(stderr,"Le pointeur que l'on tente de liberer");
                fprintf(stderr," est ecrase par l'avant \n");
                AbortFct();
                }


        SrcAlloc = Tmp + sizeof(int);

        a=(int*) ( Tmp + sizeof(int) /* CTRL */ +
                        TSRC + 1 /* Le source */
                );
        LigneAlloc = *a;
        
        a= (int*) ( Tmp + sizeof(int) /* CTRL*/+
                        TSRC +1 /* Le source */+
                        sizeof(int)
                );
        Lg = *a;

        a= (int*) ( Tmp + sizeof(int) /* CTRL*/+
                TSRC +1 /* Le source */ +
                +sizeof(int) /* Ligne du source */+
                sizeof(int) /* Longueur de l'utilisateur */+
                Lg /* les octets de l'utilisateurs */
                );
        if ( *a != CTRL ) /* L'utilisateur a ecrase par l'arriere ... */
                {
                fprintf(stderr,"\nEcrasement detecte dans %s ligne : %d\n",
                                Source,Ligne);
                fprintf(stderr,"Ce pointeur a ete alloue dans %s ligne : %d\n",
                                SrcAlloc,LigneAlloc);
                AbortFct();
                }


        return(Tmp);
        }

/********************************************************/
/********************************************************/
static SupprimerLLC(char* Ptr,char * Source,int Ligne, 
                        void (*AbortFct)(void))
        {
        sListAlloc * Courant, *Precedent;
        int Trouve;

        /* on recherche Ptr dans la liste ... */
        Precedent = &Racine;
        Courant = Racine.Suivant;
        Trouve =0;

        while ( (Courant!=NULL) && Trouve == 0)
                {
                if (Courant->Ptr == Ptr)
                        Trouve = 1;
                else
                        {
                        Precedent = Courant;
                        Courant = Courant->Suivant;
                        }
                }
        if ( Trouve ==0)
                {
                fprintf(stderr,"\nTentive de liberation d'un pointeur \n");
                fprintf(stderr,"\tnon alloue dans %s ligne : %d\n",Source,Ligne);
                AbortFct();
                }
        Precedent->Suivant = Courant->Suivant;
        free(Courant);
        
        }

/********************************************************/
/********************************************************/
static void AjouterLLC(char * Ptr)
        {
        sListAlloc * Tmp;

        Tmp = (sListAlloc *) malloc(sizeof(sListAlloc));
        if ( Tmp == NULL)
                {
                fprintf(stderr,"\n Plus de memoire ... \n");
                abort();
                }
        Tmp->Ptr = Ptr;
        Tmp->Suivant = Racine.Suivant;
        Racine.Suivant = Tmp;
        }

/********************************************************/
/********************************************************/
void _TesterMemoire(char * Source,int Ligne, void (*AbortFct)(void))
        {
        sListAlloc * Courant;
        char * SrcAlloc;
        int * a;
        int LigneAlloc,Lg;
        char * Tmp;

        Courant = Racine.Suivant;
        while( Courant != NULL)
                {
                Tmp = Courant->Ptr;
                /* On recupere le premier CTRL  */
                a=(int *) Tmp;
                if ( *a != CTRL) /* Validite des infos ? */
                        {
                        fprintf(stderr,"\nErreur Fatale dans %s ligne %d\n",
                                        Source,Ligne);
                        fprintf(stderr,"Un pointeur est ecrase par l'avant \n");
                        AbortFct();
                        }
                
                SrcAlloc = Tmp + sizeof(int);
        
                a=(int*) ( Tmp + sizeof(int) /* CTRL */ +
                                TSRC + 1 /* Le source */
                        );
                LigneAlloc = *a;
        
                a= (int*) ( Tmp + sizeof(int) /* CTRL*/+
                                TSRC +1 /* Le source */+
                                sizeof(int)
                        );
                Lg = *a;

                a= (int*) ( Tmp + sizeof(int) /* CTRL*/+
                        TSRC +1 /* Le source */ +
                        +sizeof(int) /* Ligne du source */+
                        sizeof(int) /* Longueur de l'utilisateur */+
                        Lg /* les octets de l'utilisateurs */
                        );
                if ( *a != CTRL ) /* L'utilisateur a ecrase par l'arriere ... */
                        {
                        fprintf(stderr,"\nEcrasement detecte dans %s ",Source);
                        fprintf(stderr,"ligne : %d\n",Ligne);
                        fprintf(stderr,"Ce pointeur a ete alloue dans %s ",
                                        SrcAlloc);
                        fprintf(stderr,"ligne : %d\n",LigneAlloc);
                        AbortFct();
                        }

                fprintf(stderr,"\nLe pointeur qui a ete alloue dans %s ",
                                        SrcAlloc);
                fprintf(stderr," ligne %d\n", LigneAlloc);
                fprintf(stderr," na pas ete libere\n");

                Courant = Courant->Suivant;
                }
        }

Routines d’aide au débuggage pour la gestion de la mémoire vive en C