Remplacer new et delete

Le
Guillaume GOURDIN
Bonjour à tous, je voudrais surcharger les operateurs new, new[], delete
et delete[] afin de détecter les fuites de mémoire. Idéalement, je
voudrais utiliser les macros __FILE_ et __LINE__ pour indiquer où les
fuites on été crées. Je voudrais également que l'utilisation des
nouveaux operateurs soient totalement transparante (pas d'operateur new
placé).

Comment s'effectue au niveau de la compilation le remplacement de ces
opérateurs? Et y a t'il d'autres fonctions que l'on peut remplacer de
manière globale?

Merci pour votre aide.
Vos réponses
Trier par : date / pertinence
James Kanze
Le #302084
On Jan 26, 7:28 pm, Guillaume GOURDIN
Bonjour à tous, je voudrais surcharger les operateurs new, new[], delete
et delete[] afin de détecter les fuites de mémoire.


Surcharger, ou remplacer ?

Idéalement, je
voudrais utiliser les macros __FILE_ et __LINE__ pour indiquer où les
fuites on été crées. Je voudrais également que l'utilisation des
nouveaux operateurs soient totalement transparante (pas d'operateur new
placé).


Ce que tu veux, alors, c'est remplacé les opérateurs prédéfinis,
non les surcharger. Il n'y a aucun moyen d'ajouter des
paramètres de façon « transparentes ». (Certains essaient au
moyen des macros et un new de placement. Le problème, c'est que
ça heurte aux autres utilisations des new de placement, dans la
bibliothèque standard, par exemple.)

Ce que j'ai fait, moi, c'est d'implémenter un stack walkback. Ce
qu'on ne peut pas faire de façon portable, mais g++ a une
fonction dans sa bibliothèque pour le faire, et j'ai des
implémentations Intel et Sparc sur ma site, si tu veux les
prendre. (http://kanze.james.neuf.fr/code-fr.html : chercher
dans le soussystème Port.)

Comment s'effectue au niveau de la compilation le remplacement de ces
opérateurs?


Formellement, c'est défini par l'implémentation, mais dans la
pratique, dans toutes les implémentations, ce n'est pas au
niveau de la compilation proprement dite, mais plutôt lors de
l'édition des liens : on s'arrange pour qu'il y a un fichier
object qui en contient les définitions (de new et de delete --
les deux vont de pair) avant l'inclusion de la bibliothèque
standard (mais après l'inclusion d'au moins un fichier objet qui
les utilise).

Et y a t'il d'autres fonctions que l'on peut remplacer de
manière globale?


De la même façon que new/delete, rien ne me vient à l'ésprit,
mais on peut aussi remplacer certaines fonctions en précisant
un remplacement dynamiquement : voir set_new_handler,
set_unexpected et set_terminate.

--
James Kanze (Gabi Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Aurelien Regat-Barrel
Le #302043
Bonjour,

Bonjour à tous, je voudrais surcharger les operateurs new, new[], delete
et delete[] afin de détecter les fuites de mémoire. Idéalement, je
voudrais utiliser les macros __FILE_ et __LINE__ pour indiquer où les
fuites on été crées. Je voudrais également que l'utilisation des
nouveaux operateurs soient totalement transparante (pas d'operateur new
placé).

Comment s'effectue au niveau de la compilation le remplacement de ces
opérateurs? Et y a t'il d'autres fonctions que l'on peut remplacer de
manière globale?


Methode simple qui marche avec VC++:
placer:

#define _CRTDBG_MAP_ALLOC
#include #define new new( _CLIENT_BLOCK, __FILE__, __LINE__)

dans un fichier d'entete dont l'inclusion est rendue implicite dans tous
les fichiers de ton projet (options->C/C++->Avancé->Fichiers Include
forcés).
http://msdn2.microsoft.com/en-us/library/8c5ztk84.aspx

Puis dans le main.cpp, rajouter:

// Automatically dumps leaks on program exit
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag( tmpFlag );

pour qu'en fin d'execution la liste des fuites memoires soit affichée
dans la sortie de débogueur.
Tu peux avoir la liste des fuites sans faire de #define new, mais il
faut alors te contenter du numero d'allocation, au lieu de l'info
fichier + numéro de ligne.

--
Aurelien Regat-Barrel

James Kanze
Le #302041
Aurelien Regat-Barrel wrote:

Bonjour à tous, je voudrais surcharger les operateurs new, new[], de lete
et delete[] afin de détecter les fuites de mémoire. Idéalement, je
voudrais utiliser les macros __FILE_ et __LINE__ pour indiquer où les
fuites on été crées. Je voudrais également que l'utilisation d es
nouveaux operateurs soient totalement transparante (pas d'operateur new
placé).

Comment s'effectue au niveau de la compilation le remplacement de ces
opérateurs? Et y a t'il d'autres fonctions que l'on peut remplacer de
manière globale?


Methode simple qui marche avec VC++:
placer:

#define _CRTDBG_MAP_ALLOC
#include #define new new( _CLIENT_BLOCK, __FILE__, __LINE__)

dans un fichier d'entete dont l'inclusion est rendue implicite dans tous
les fichiers de ton projet (options->C/C++->Avancé->Fichiers Include
forcés).


Y compris dans ceux des bibliothèques dont tu n'as pas les
sources ?

http://msdn2.microsoft.com/en-us/library/8c5ztk84.aspx

Puis dans le main.cpp, rajouter:

// Automatically dumps leaks on program exit
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag( tmpFlag );

pour qu'en fin d'execution la liste des fuites memoires soit affichée
dans la sortie de débogueur.


Et que se passe-t-il en cas des choses comme :

#include <map>

? Au moins d'être sûr (mais comment) que tout fichier qui
utilise new (dans une fonction inline, ou dans un template) a
été inclu avant le #define, c'est garanti de ne pas marcher.
C'est aussi garanti de ne pas marcher dans les cas où une classe
utilisateur spécifie un new propre à la classe (chose quand même
assez fréquente).

En somme, c'est une technique à éviter.

Tu peux avoir la liste des fuites sans faire de #define new, mais il
faut alors te contenter du numero d'allocation, au lieu de l'info
fichier + numéro de ligne.


Je ne sais pas. Moi, j'arrive à avoir une trace de la pile, sans
le moindre macro.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Aurelien Regat-Barrel
Le #301998
Methode simple qui marche avec VC++:
placer:

#define _CRTDBG_MAP_ALLOC
#include #define new new( _CLIENT_BLOCK, __FILE__, __LINE__)

dans un fichier d'entete dont l'inclusion est rendue implicite dans tous
les fichiers de ton projet (options->C/C++->Avancé->Fichiers Include
forcés).


Y compris dans ceux des bibliothèques dont tu n'as pas les
sources ?


Ben non, ca nessecite une recompilation du code, mais tu l'avais compris
je pense :-)

http://msdn2.microsoft.com/en-us/library/8c5ztk84.aspx

Puis dans le main.cpp, rajouter:

// Automatically dumps leaks on program exit
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag( tmpFlag );

pour qu'en fin d'execution la liste des fuites memoires soit affichée
dans la sortie de débogueur.


Et que se passe-t-il en cas des choses comme :

#include <map>


Ca fonctionne. Je suppose que la STL de VC++ prend en compte cet aspect.
D'ailleurs, le fichier source <map> n'est pas mentionné quand la fuite
provient d'une allocation effectuée dans la map, donc il y a bien une
astuce qui fait que le new utilisé n'est pas impacté par le #define. Et
ca ne semble pas etre un simple #undef. Je n'ai malheureusement pas le
temps de chercher...


? Au moins d'être sûr (mais comment) que tout fichier qui
utilise new (dans une fonction inline, ou dans un template) a
été inclu avant le #define, c'est garanti de ne pas marcher.
C'est aussi garanti de ne pas marcher dans les cas où une classe
utilisateur spécifie un new propre à la classe (chose quand même
assez fréquente).


Dans mon cas, ca a posé probleme avec free() et realloc() qui sont aussi
implicitement renomées par le #define _CRTDBG_MAP_ALLOC, et qui étaient
des noms de fonctions membres dans une des bibliotheques utilisées.

En somme, c'est une technique à éviter.


Je l'ai juste mentionnée car elle est intégrée au compilo et tres facile
a mettre en oeuvre. A ce sujet, si vous avez une bonne bibliotheque a me
conseiller (gratuite)...

Tu peux avoir la liste des fuites sans faire de #define new, mais il
faut alors te contenter du numero d'allocation, au lieu de l'info
fichier + numéro de ligne.


Je ne sais pas. Moi, j'arrive à avoir une trace de la pile, sans
le moindre macro.


Ce que propose VC++, c'est d'identifier le numéro de l'allocation
fautive, et deposer un break point dessus, a l'execution suivante. C'est
assez rustique, mais ca marche assez bien si tu peux facilement
effectuer 2 exécutions strictement identiques de ton programme. Si tu as
beaucoup de fuites dans ton programme, ce n'est clairement pas suffisant.

--
Aurelien Regat-Barrel


James Kanze
Le #301996
On Jan 29, 12:45 pm, Aurelien Regat-Barrel <nospam-
wrote:
Methode simple qui marche avec VC++:
placer:

#define _CRTDBG_MAP_ALLOC
#include #define new new( _CLIENT_BLOCK, __FILE__, __LINE__)

dans un fichier d'entete dont l'inclusion est rendue implicite dans to us
les fichiers de ton projet (options->C/C++->Avancé->Fichiers Include
forcés).


Y compris dans ceux des bibliothèques dont tu n'as pas les
sources ?


Ben non, ca nessecite une recompilation du code, mais tu l'avais compris
je pense :-)


Certes. Mais c'est une restriction importante.

http://msdn2.microsoft.com/en-us/library/8c5ztk84.aspx

Puis dans le main.cpp, rajouter:

// Automatically dumps leaks on program exit
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag( tmpFlag );

pour qu'en fin d'execution la liste des fuites memoires soit affichée
dans la sortie de débogueur.


Et que se passe-t-il en cas des choses comme :

#include <map>Ca fonctionne. Je suppose que la STL de
VC++ prend en compte cet aspect.


D'ailleurs, le fichier source <map> n'est pas mentionné quand la fuite
provient d'une allocation effectuée dans la map, donc il y a bien une
astuce qui fait que le new utilisé n'est pas impacté par le #define. Et
ca ne semble pas etre un simple #undef. Je n'ai malheureusement pas le
temps de chercher...


Peut-être en en forçant les inclusions dans leur tout simplement. Ce qui fait que ça ne vaut que pour les classes
de la bibliothèque standard ; tu fais quelque chose
d'équivalent, et tu as des problèmes.

? Au moins d'être sûr (mais comment) que tout fichier qui
utilise new (dans une fonction inline, ou dans un template) a
été inclu avant le #define, c'est garanti de ne pas marcher.
C'est aussi garanti de ne pas marcher dans les cas où une classe
utilisateur spécifie un new propre à la classe (chose quand même
assez fréquente).


Dans mon cas, ca a posé probleme avec free() et realloc() qui sont aussi
implicitement renomées par le #define _CRTDBG_MAP_ALLOC, et qui étaie nt
des noms de fonctions membres dans une des bibliotheques utilisées.

En somme, c'est une technique à éviter.


Je l'ai juste mentionnée car elle est intégrée au compilo et tres f acile
a mettre en oeuvre. A ce sujet, si vous avez une bonne bibliotheque a me
conseiller (gratuite)...


Pour commencer, il y a la mienne:-). (kanze.james.neuf.fr.) Mais
j'ai l'impression que valgrind me laisse loin derrière.

Tu peux avoir la liste des fuites sans faire de #define new, mais il
faut alors te contenter du numero d'allocation, au lieu de l'info
fichier + numéro de ligne.


Je ne sais pas. Moi, j'arrive à avoir une trace de la pile, sans
le moindre macro.


Ce que propose VC++, c'est d'identifier le numéro de l'allocation
fautive, et deposer un break point dessus, a l'execution suivante. C'est
assez rustique, mais ca marche assez bien si tu peux facilement
effectuer 2 exécutions strictement identiques de ton programme. Si tu as
beaucoup de fuites dans ton programme, ce n'est clairement pas suffisant.


C'est plus qu'« assez rustique », étant donné la technologie à
la disposition de Microsoft. Franchement, ils auraient pu faire
beaucoup mieux.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Dominique Vaufreydaz
Le #301995
Bonjour,

après débat ici, j'ai fait une version portable pour new/delete.
L'idée était de tracer les fuite. Par contre, j'ai finalement finit
par opter pour une instrumentation du code. Tu mets un
FLAGS devant l'appel a tes new pour qu'ils soitent pris en compte.

Si ca t'intéresse, tu peux regarder ce que ca donne dans la partie
System de notre middleware OMISCID (google est ton ami). Il
faut mettre un flag a la compil.

Si tu as des bugs la dessus, je suis prenneurs de tout retour.

Doms.

PS: tu peux compiler que la partie ssystem a loisir sinon,
il va te falloir toute une clique de libraury (libxml2, bonjour).
Mathias Gaunard
Le #301990
Bonjour à tous, je voudrais surcharger les operateurs new, new[], delete
et delete[] afin de détecter les fuites de mémoire. Idéalement, je
voudrais utiliser les macros __FILE_ et __LINE__ pour indiquer où les
fuites on été crées. Je voudrais également que l'utilisation des
nouveaux operateurs soient totalement transparante (pas d'operateur new
placé).


Il est bien plus intéressant d'utiliser un debogueur, qui fournira bien
plus d'informations d'utiles et de manière plus transparente.

valgrind en particulier est très pratique pour les fuites mémoires.

Publicité
Poster une réponse
Anonyme