Arnaud Meurgues wrote:wrote:
Au moins sous Linux.
pour info, sous NT, il y a une fonction StackWalk qui permet de
Arnaud Meurgues wrote:
kanze@gabi-soft.fr wrote:
Au moins sous Linux.
pour info, sous NT, il y a une fonction StackWalk qui permet de
Arnaud Meurgues wrote:wrote:
Au moins sous Linux.
pour info, sous NT, il y a une fonction StackWalk qui permet de
Dans le message 42d5044f$0$31208$,Michel Michaud wrote:Juste un mot pour préciser qu'il y a déjà ce qu'il faut sous
Visual C++, si jamais c'est ce que tu utilises...
Est ce que vous parlez de :
_CrtSetReportMode()
_malloc_dbg()
Plutôt
#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...
À la fin de l'exécution (en mode debug), on a une liste des
zones allouées non libérées, donc les fuites habituellement.
Dans le message 42d5044f$0$31208$636a15ce@news.free.fr,
Michel Michaud wrote:
Juste un mot pour préciser qu'il y a déjà ce qu'il faut sous
Visual C++, si jamais c'est ce que tu utilises...
Est ce que vous parlez de :
_CrtSetReportMode()
_malloc_dbg()
Plutôt
#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...
À la fin de l'exécution (en mode debug), on a une liste des
zones allouées non libérées, donc les fuites habituellement.
Dans le message 42d5044f$0$31208$,Michel Michaud wrote:Juste un mot pour préciser qu'il y a déjà ce qu'il faut sous
Visual C++, si jamais c'est ce que tu utilises...
Est ce que vous parlez de :
_CrtSetReportMode()
_malloc_dbg()
Plutôt
#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...
À la fin de l'exécution (en mode debug), on a une liste des
zones allouées non libérées, donc les fuites habituellement.
#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...
À la fin de l'exécution (en mode debug), on a une liste des
zones allouées non libérées, donc les fuites habituellement.
heu moi je suis pas encore tres doué
il suffit de mettre ca dans le main() ???
#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...
À la fin de l'exécution (en mode debug), on a une liste des
zones allouées non libérées, donc les fuites habituellement.
heu moi je suis pas encore tres doué
il suffit de mettre ca dans le main() ???
#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...
À la fin de l'exécution (en mode debug), on a une liste des
zones allouées non libérées, donc les fuites habituellement.
heu moi je suis pas encore tres doué
il suffit de mettre ca dans le main() ???
Dans le message 42d6c863$0$2421$,#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...
À la fin de l'exécution (en mode debug), on a une liste des
zones allouées non libérées, donc les fuites habituellement.
heu moi je suis pas encore tres doué
il suffit de mettre ca dans le main() ???
Oui, c'est tout. Il faut ensuite exécuter en mode debug.
S'il y a des fuites, elles te seront indiqués. Par exemple :
#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
new long(0x224D4D22);
new long; // ou std::malloc(sizeof(long));
}
Donne (dans la fenêtre de debug) :
Detected memory leaks!
Dumping objects ->
{51} normal block at 0x00321030, 4 bytes long.
Data: < > CD CD CD CD
{50} normal block at 0x00320FF0, 4 bytes long.
Data: <"MM"> 22 4D 4D 22
Object dump complete.
La mémoire non initialisée est indiquée par des CD; les lignes
Data montrent le contenu en texte si possible (entre <>) et en
hexa; les {nn} sont les numéros de blocs alloués si je me souviens
bien. Avec les adresses des blocs et ces informations, on a déjà de
quoi se mettre sous la dent pour trouver d'où viennent les fuites.
C'est pas mal pour un outil gratuit et déjà intégré, mais c'est
avec VC seulement (il y a peut-être un équivalent avec d'autres
compilateurs).
ok merci je vais donc essayer ca aussi :-)
Dans le message 42d6c863$0$2421$626a14ce@news.free.fr,
#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...
À la fin de l'exécution (en mode debug), on a une liste des
zones allouées non libérées, donc les fuites habituellement.
heu moi je suis pas encore tres doué
il suffit de mettre ca dans le main() ???
Oui, c'est tout. Il faut ensuite exécuter en mode debug.
S'il y a des fuites, elles te seront indiqués. Par exemple :
#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
new long(0x224D4D22);
new long; // ou std::malloc(sizeof(long));
}
Donne (dans la fenêtre de debug) :
Detected memory leaks!
Dumping objects ->
{51} normal block at 0x00321030, 4 bytes long.
Data: < > CD CD CD CD
{50} normal block at 0x00320FF0, 4 bytes long.
Data: <"MM"> 22 4D 4D 22
Object dump complete.
La mémoire non initialisée est indiquée par des CD; les lignes
Data montrent le contenu en texte si possible (entre <>) et en
hexa; les {nn} sont les numéros de blocs alloués si je me souviens
bien. Avec les adresses des blocs et ces informations, on a déjà de
quoi se mettre sous la dent pour trouver d'où viennent les fuites.
C'est pas mal pour un outil gratuit et déjà intégré, mais c'est
avec VC seulement (il y a peut-être un équivalent avec d'autres
compilateurs).
ok merci je vais donc essayer ca aussi :-)
Dans le message 42d6c863$0$2421$,#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
...
À la fin de l'exécution (en mode debug), on a une liste des
zones allouées non libérées, donc les fuites habituellement.
heu moi je suis pas encore tres doué
il suffit de mettre ca dans le main() ???
Oui, c'est tout. Il faut ensuite exécuter en mode debug.
S'il y a des fuites, elles te seront indiqués. Par exemple :
#include <crtdbg.h>
int main()
{
int debugHeapFlag= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(debugHeapFlag | _CRTDBG_LEAK_CHECK_DF);
new long(0x224D4D22);
new long; // ou std::malloc(sizeof(long));
}
Donne (dans la fenêtre de debug) :
Detected memory leaks!
Dumping objects ->
{51} normal block at 0x00321030, 4 bytes long.
Data: < > CD CD CD CD
{50} normal block at 0x00320FF0, 4 bytes long.
Data: <"MM"> 22 4D 4D 22
Object dump complete.
La mémoire non initialisée est indiquée par des CD; les lignes
Data montrent le contenu en texte si possible (entre <>) et en
hexa; les {nn} sont les numéros de blocs alloués si je me souviens
bien. Avec les adresses des blocs et ces informations, on a déjà de
quoi se mettre sous la dent pour trouver d'où viennent les fuites.
C'est pas mal pour un outil gratuit et déjà intégré, mais c'est
avec VC seulement (il y a peut-être un équivalent avec d'autres
compilateurs).
ok merci je vais donc essayer ca aussi :-)
pour info, sous NT, il y a une fonction StackWalk qui permet de
parcourir la pile:
pour info, sous NT, il y a une fonction StackWalk qui permet de
parcourir la pile:
pour info, sous NT, il y a une fonction StackWalk qui permet de
parcourir la pile:
wrote:l'autre. En dur, direct dans le code -- je n'avais pas pensé
au visiteur.
Oui. J'ai longtemps hésité sur la manière d'utiliser le
visiteur. Je me demandais si c'était à lui de stocker les
blocs ou si cela devait être fait par l'allocateur. Je n'ai
pas trouvé de réponse satisfaisante.
Peut-être que les stocker dans l'allocateur et ne fournir au
visiteur que des itérateurs sur la liste des blocs mémoire de
l'allocateur serait une meilleure solution ?
Le principe de base est assez simple : il faut
éventuellement s'assurer que toute la pile est en mémoire
(toujours le cas sur des IA-32, mais il faut une instruction
machine spéciale sur un Sparc).
Ah ? Sur Sparc, toute la pile n'est pas nécessairement en
mémoire ?
Ensuite, tu obtiens l'adresse de départ -- soit en pêchant
dans un buffer de setjmp,
Ah. Je ne suis pas (plus) très familier avec ce genre de
fonctions. Je n'ai jamais eu à m'en servir.
d'une variable locale. Puis, il ne reste plus que des
reinterpret_cast et de l'arithmétique sur des pointeurs pour
régarder ce que tu veux dans la pile. En fait, la plus
difficile, en général, c'est de savoir où se trouvent
exactement dans la pile les informations que tu cherches.
Ben oui. Ça nécessite une bonne documentation du compilateur,
de l'OS et du matériel pour savoir comment il organise la
pile.
Au moins sous Linux. Mais j'imagine que la seule chose qui
risque de changer sous Windows, c'est ce que tu ajoutes à
l'adresse de fp dans le constructeur. (Selon le compilateur,
il se peut aussi qu'il vaut mieux que le constructeur ne
soit pas inline, voir qu'on se sert d'une fonction
complétement séparée pour obtenir l'adresse de début. Mais
le code ici fonctionne sous Linux avec des versions récentes
de g++, compilé sans optimisation.)
Note aussi qu'avec g++, tu as des fonctions
__builtin_return_address et __builtin_frame_address, chacun
qui prend un paramètre pour spécifier le profondeur.
Malheureusement, il se trouve que g++ est un des compilateurs
que je n'utilise pas (moi, c'est msvc sous Windows, CC sous
Solaris, aCC sous HP, essentiellement).
En plus, j'aurais aimé trouver les noms des fonctions, plutôt
que simplement les adresses. Et ça, ça nécessite de savoir
lire les infos de debug...
kanze@gabi-soft.fr wrote:
l'autre. En dur, direct dans le code -- je n'avais pas pensé
au visiteur.
Oui. J'ai longtemps hésité sur la manière d'utiliser le
visiteur. Je me demandais si c'était à lui de stocker les
blocs ou si cela devait être fait par l'allocateur. Je n'ai
pas trouvé de réponse satisfaisante.
Peut-être que les stocker dans l'allocateur et ne fournir au
visiteur que des itérateurs sur la liste des blocs mémoire de
l'allocateur serait une meilleure solution ?
Le principe de base est assez simple : il faut
éventuellement s'assurer que toute la pile est en mémoire
(toujours le cas sur des IA-32, mais il faut une instruction
machine spéciale sur un Sparc).
Ah ? Sur Sparc, toute la pile n'est pas nécessairement en
mémoire ?
Ensuite, tu obtiens l'adresse de départ -- soit en pêchant
dans un buffer de setjmp,
Ah. Je ne suis pas (plus) très familier avec ce genre de
fonctions. Je n'ai jamais eu à m'en servir.
d'une variable locale. Puis, il ne reste plus que des
reinterpret_cast et de l'arithmétique sur des pointeurs pour
régarder ce que tu veux dans la pile. En fait, la plus
difficile, en général, c'est de savoir où se trouvent
exactement dans la pile les informations que tu cherches.
Ben oui. Ça nécessite une bonne documentation du compilateur,
de l'OS et du matériel pour savoir comment il organise la
pile.
Au moins sous Linux. Mais j'imagine que la seule chose qui
risque de changer sous Windows, c'est ce que tu ajoutes à
l'adresse de fp dans le constructeur. (Selon le compilateur,
il se peut aussi qu'il vaut mieux que le constructeur ne
soit pas inline, voir qu'on se sert d'une fonction
complétement séparée pour obtenir l'adresse de début. Mais
le code ici fonctionne sous Linux avec des versions récentes
de g++, compilé sans optimisation.)
Note aussi qu'avec g++, tu as des fonctions
__builtin_return_address et __builtin_frame_address, chacun
qui prend un paramètre pour spécifier le profondeur.
Malheureusement, il se trouve que g++ est un des compilateurs
que je n'utilise pas (moi, c'est msvc sous Windows, CC sous
Solaris, aCC sous HP, essentiellement).
En plus, j'aurais aimé trouver les noms des fonctions, plutôt
que simplement les adresses. Et ça, ça nécessite de savoir
lire les infos de debug...
wrote:l'autre. En dur, direct dans le code -- je n'avais pas pensé
au visiteur.
Oui. J'ai longtemps hésité sur la manière d'utiliser le
visiteur. Je me demandais si c'était à lui de stocker les
blocs ou si cela devait être fait par l'allocateur. Je n'ai
pas trouvé de réponse satisfaisante.
Peut-être que les stocker dans l'allocateur et ne fournir au
visiteur que des itérateurs sur la liste des blocs mémoire de
l'allocateur serait une meilleure solution ?
Le principe de base est assez simple : il faut
éventuellement s'assurer que toute la pile est en mémoire
(toujours le cas sur des IA-32, mais il faut une instruction
machine spéciale sur un Sparc).
Ah ? Sur Sparc, toute la pile n'est pas nécessairement en
mémoire ?
Ensuite, tu obtiens l'adresse de départ -- soit en pêchant
dans un buffer de setjmp,
Ah. Je ne suis pas (plus) très familier avec ce genre de
fonctions. Je n'ai jamais eu à m'en servir.
d'une variable locale. Puis, il ne reste plus que des
reinterpret_cast et de l'arithmétique sur des pointeurs pour
régarder ce que tu veux dans la pile. En fait, la plus
difficile, en général, c'est de savoir où se trouvent
exactement dans la pile les informations que tu cherches.
Ben oui. Ça nécessite une bonne documentation du compilateur,
de l'OS et du matériel pour savoir comment il organise la
pile.
Au moins sous Linux. Mais j'imagine que la seule chose qui
risque de changer sous Windows, c'est ce que tu ajoutes à
l'adresse de fp dans le constructeur. (Selon le compilateur,
il se peut aussi qu'il vaut mieux que le constructeur ne
soit pas inline, voir qu'on se sert d'une fonction
complétement séparée pour obtenir l'adresse de début. Mais
le code ici fonctionne sous Linux avec des versions récentes
de g++, compilé sans optimisation.)
Note aussi qu'avec g++, tu as des fonctions
__builtin_return_address et __builtin_frame_address, chacun
qui prend un paramètre pour spécifier le profondeur.
Malheureusement, il se trouve que g++ est un des compilateurs
que je n'utilise pas (moi, c'est msvc sous Windows, CC sous
Solaris, aCC sous HP, essentiellement).
En plus, j'aurais aimé trouver les noms des fonctions, plutôt
que simplement les adresses. Et ça, ça nécessite de savoir
lire les infos de debug...
Arnaud Meurgues writes:
[...]
| > Note aussi qu'avec g++, tu as des fonctions
| > __builtin_return_address et __builtin_frame_address, chacun qui
| > prend un paramètre pour spécifier le profondeur.
mais ces machins ne marchent pas bien pour une profondeur
autre que zéro.
Arnaud Meurgues <news.arnaud@meurgues.non.fr.invalid> writes:
[...]
| > Note aussi qu'avec g++, tu as des fonctions
| > __builtin_return_address et __builtin_frame_address, chacun qui
| > prend un paramètre pour spécifier le profondeur.
mais ces machins ne marchent pas bien pour une profondeur
autre que zéro.
Arnaud Meurgues writes:
[...]
| > Note aussi qu'avec g++, tu as des fonctions
| > __builtin_return_address et __builtin_frame_address, chacun qui
| > prend un paramètre pour spécifier le profondeur.
mais ces machins ne marchent pas bien pour une profondeur
autre que zéro.
writes:
| Gabriel Dos Reis wrote:
| > Arnaud Meurgues writes:
| > [...]
| > | > Note aussi qu'avec g++, tu as des fonctions
| > | > __builtin_return_address et __builtin_frame_address, chacun qui
| > | > prend un paramètre pour spécifier le profondeur.
| > mais ces machins ne marchent pas bien pour une profondeur
| > autre que zéro.
| Ils ne sont garantis que pour une profondeur de zéro. Mais
| d'après ce que j'ai compris, il marche plus ou moins bien,
| selon la plateforme.
Tu as compris quelque chose ; moi j'ai essayé en vrai sur
quelques machines et de plus j'ai eu des bugs reports.
| Si ta plateforme est une où il marche plutôt bien, ça serait
| bête de s'en priver
Tout à fait exact, mais il me semble devoir signaler l'aspect
restrictif de la chose parce que j'ai déjà reçu beaucoup de
bug reports (visiblement d'utilisateurs qui ont préféré
oublier cet aspect de la chose).
kanze@gabi-soft.fr writes:
| Gabriel Dos Reis wrote:
| > Arnaud Meurgues <news.arnaud@meurgues.non.fr.invalid> writes:
| > [...]
| > | > Note aussi qu'avec g++, tu as des fonctions
| > | > __builtin_return_address et __builtin_frame_address, chacun qui
| > | > prend un paramètre pour spécifier le profondeur.
| > mais ces machins ne marchent pas bien pour une profondeur
| > autre que zéro.
| Ils ne sont garantis que pour une profondeur de zéro. Mais
| d'après ce que j'ai compris, il marche plus ou moins bien,
| selon la plateforme.
Tu as compris quelque chose ; moi j'ai essayé en vrai sur
quelques machines et de plus j'ai eu des bugs reports.
| Si ta plateforme est une où il marche plutôt bien, ça serait
| bête de s'en priver
Tout à fait exact, mais il me semble devoir signaler l'aspect
restrictif de la chose parce que j'ai déjà reçu beaucoup de
bug reports (visiblement d'utilisateurs qui ont préféré
oublier cet aspect de la chose).
writes:
| Gabriel Dos Reis wrote:
| > Arnaud Meurgues writes:
| > [...]
| > | > Note aussi qu'avec g++, tu as des fonctions
| > | > __builtin_return_address et __builtin_frame_address, chacun qui
| > | > prend un paramètre pour spécifier le profondeur.
| > mais ces machins ne marchent pas bien pour une profondeur
| > autre que zéro.
| Ils ne sont garantis que pour une profondeur de zéro. Mais
| d'après ce que j'ai compris, il marche plus ou moins bien,
| selon la plateforme.
Tu as compris quelque chose ; moi j'ai essayé en vrai sur
quelques machines et de plus j'ai eu des bugs reports.
| Si ta plateforme est une où il marche plutôt bien, ça serait
| bête de s'en priver
Tout à fait exact, mais il me semble devoir signaler l'aspect
restrictif de la chose parce que j'ai déjà reçu beaucoup de
bug reports (visiblement d'utilisateurs qui ont préféré
oublier cet aspect de la chose).