118 votes

Comment retrouver une erreur de type "double free ou corruption" ?

Lorsque j'exécute mon programme (C++), il se bloque avec cette erreur.

* glibc detected * ./load : double free ou corruption (!prev) : 0x0000000000c6ed50 ***

Comment puis-je retrouver l'erreur ?

J'ai essayé d'utiliser print ( std::cout ), sans succès. Pourrait-on gdb pour rendre cela plus facile ?

8 votes

Je me demande pourquoi tout le monde suggère de NULL (ce qui masque des erreurs qui seraient autrement détectées, comme le montre bien cette question), mais personne ne suggère de ne pas faire de gestion manuelle de la mémoire du tout, ce qui est très bien possible en C++. Je n'ai pas écrit delete en années. (Et, oui, mon code est critique en termes de performances. Sinon, il n'aurait pas été écrit en C++).

2 votes

@sbi : La corruption de tas et autres sont rarement pris, du moins pas là où ils se produisent. NULL L'utilisation de pointeurs peut faire planter votre programme plus tôt.

0 votes

@Hasturkun : Je ne suis pas du tout d'accord. Une incitation majeure à NULL est d'empêcher une deuxième delete ptr; d'exploser - ce qui masque une erreur, parce que cette seconde delete n'aurait jamais dû se produire. (Il est également utilisé pour vérifier si un pointeur pointe toujours vers un objet valide. Mais cela ne fait que soulever la question de savoir pourquoi vous avez un pointeur dans la portée qui n'a pas d'objet à pointer).

79voto

Hasturkun Points 18653

Si vous utilisez la glibc, vous pouvez définir le paramètre MALLOC_CHECK_ à la variable d'environnement 2 ce qui amènera la glibc à utiliser une version tolérante à l'erreur de malloc ce qui fera que votre programme s'arrêtera au moment où le double free est effectué.

Vous pouvez définir ce paramètre à partir de gdb en utilisant la fonction set environment MALLOC_CHECK_ 2 avant d'exécuter votre programme ; le programme devrait s'arrêter, avec la commande free() visible dans le backtrace.

voir le page de manuel pour malloc() pour plus d'informations

3 votes

Réglage de MALLOC_CHECK_2 a effectivement corrigé mon problème de double free (bien qu'il ne soit pas corrigé s'il est en mode débogage seulement)

4 votes

@puk J'ai le même problème, mettre MALLOC_CHECK_ à 2 évite mon problème de double-free. Quelles sont les autres options pour injecter le moins de code possible afin de reproduire le problème et de fournir un backtrace ?

0 votes

Il arrive aussi que le réglage de MALLOC_CHECK_ évite le problème. Amis commentateurs/tout le monde... avez-vous trouvé une autre façon d'exposer le problème ?

38voto

Kornel Kisielewicz Points 26556

Il y a au moins deux situations possibles :

  1. vous supprimez deux fois la même entité
  2. vous supprimez quelque chose qui n'était pas alloué.

Pour la première, je suggère fortement de mettre à NULL tous les pointeurs supprimés.

Vous avez trois options :

  1. surcharge new et delete et suivi des allocations
  2. oui, utilisez gdb -- vous obtiendrez alors un backtrace de votre crash, et cela sera probablement très utile
  3. comme suggéré -- utilisez Valgrind -- il n'est pas facile d'y accéder, mais cela vous fera gagner mille fois du temps à l'avenir...

0 votes

2. causerait une corruption, mais je ne pense pas que ce message apparaisse généralement, puisque la vérification de l'intégrité n'est effectuée que sur le tas. Cependant, je pense que le 3. débordement de tampon du tas est possible.

0 votes

Un bon. Il est vrai que j'ai manqué de rendre le pointeur NULL et j'ai été confronté à cette erreur. Leçons apprises !

31voto

Matthew Flaschen Points 131723

Vous pouvez utiliser gdb, mais je commencerais par essayer Valgrind . Voir le guide de démarrage rapide .

En bref, Valgrind instrumente votre programme afin de détecter plusieurs types d'erreurs dans l'utilisation de la mémoire allouée dynamiquement, comme les doubles libérations et les écritures au-delà de la fin des blocs de mémoire alloués (ce qui peut corrompre le tas). Il détecte et signale les erreurs dès qu'ils se produisent Vous serez ainsi directement orienté vers la cause du problème.

0 votes

On peut aussi utiliser lldb si on préfère llvm à gnu.

0 votes

Pour moi, l'erreur consistait à libérer la mémoire correctement allouée à un pointeur qui était correctement configuré (pas NULL) et correctement libéré - une seule fois et pas deux... Valgrind a montré qu'un autre pointeur avait la mauvaise quantité de mémoire allouée..., ce qui a conduit au message d'erreur ci-dessus... - j'ai corrigé l'allocation incorrecte pour un pointeur complètement différent et le problème a été résolu. merci beaucoup pour cette réponse utile :-)

1 votes

@SMR, dans ce cas, les parties essentielles de la réponse sont l'ensemble de la grande page liée. Il est donc parfaitement possible de n'inclure que le lien dans la réponse. Quelques mots sur les raisons pour lesquelles l'auteur préfère Valgrind à gdb et sur la façon dont il s'attaquerait au problème. spécifique Le problème est, à mon avis, ce qui manque vraiment à la réponse.

25voto

Jack Points 688

Trois règles de base :

  1. Mettre le pointeur sur NULL après libre
  2. Vérifiez NULL avant de libérer.
  3. Initialise le pointeur sur NULL au départ.

La combinaison de ces trois éléments fonctionne très bien.

1 votes

Je ne suis pas un expert, mais j'arrive généralement à garder la tête hors de l'eau. Pourquoi le numéro 1 ? Est-ce que c'est pour que votre programme se plante carrément quand vous essayez d'accéder à un pointeur libre, et pas seulement une erreur silencieuse ?

1 votes

@Précision : Oui, c'est le but. C'est une bonne pratique : avoir un pointeur sur une mémoire effacée est un risque.

0 votes

@ereOn : Merci. J'ai juste eu quelques cours sur le C, et je n'ai jamais eu à écrire du code qu'avec quelqu'un d'autre, donc je n'ai jamais vraiment eu ce problème. Cela semble être une très bonne pratique cependant.

18voto

Vous pouvez utiliser valgrind pour le déboguer.

#include<stdio.h>
#include<stdlib.h>

int main()
{
 char *x = malloc(100);
 free(x);
 free(x);
 return 0;
}

[sand@PS-CNTOS-64-S11 testbox]$ vim t1.c
[sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1
[sand@PS-CNTOS-64-S11 testbox]$ ./t1
*** glibc detected *** ./t1: double free or corruption (top): 0x00000000058f7010 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3a3127245f]
/lib64/libc.so.6(cfree+0x4b)[0x3a312728bb]
./t1[0x400500]
/lib64/libc.so.6(__libc_start_main+0xf4)[0x3a3121d994]
./t1[0x400429]
======= Memory map: ========
00400000-00401000 r-xp 00000000 68:02 30246184                           /home/sand/testbox/t1
00600000-00601000 rw-p 00000000 68:02 30246184                           /home/sand/testbox/t1
058f7000-05918000 rw-p 058f7000 00:00 0                                  [heap]
3a30e00000-3a30e1c000 r-xp 00000000 68:03 5308733                        /lib64/ld-2.5.so
3a3101b000-3a3101c000 r--p 0001b000 68:03 5308733                        /lib64/ld-2.5.so
3a3101c000-3a3101d000 rw-p 0001c000 68:03 5308733                        /lib64/ld-2.5.so
3a31200000-3a3134e000 r-xp 00000000 68:03 5310248                        /lib64/libc-2.5.so
3a3134e000-3a3154e000 ---p 0014e000 68:03 5310248                        /lib64/libc-2.5.so
3a3154e000-3a31552000 r--p 0014e000 68:03 5310248                        /lib64/libc-2.5.so
3a31552000-3a31553000 rw-p 00152000 68:03 5310248                        /lib64/libc-2.5.so
3a31553000-3a31558000 rw-p 3a31553000 00:00 0
3a41c00000-3a41c0d000 r-xp 00000000 68:03 5310264                        /lib64/libgcc_s-4.1.2-20080825.so.1
3a41c0d000-3a41e0d000 ---p 0000d000 68:03 5310264                        /lib64/libgcc_s-4.1.2-20080825.so.1
3a41e0d000-3a41e0e000 rw-p 0000d000 68:03 5310264                        /lib64/libgcc_s-4.1.2-20080825.so.1
2b1912300000-2b1912302000 rw-p 2b1912300000 00:00 0
2b191231c000-2b191231d000 rw-p 2b191231c000 00:00 0
7ffffe214000-7ffffe229000 rw-p 7ffffffe9000 00:00 0                      [stack]
7ffffe2b0000-7ffffe2b4000 r-xp 7ffffe2b0000 00:00 0                      [vdso]
ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0                  [vsyscall]
Aborted
[sand@PS-CNTOS-64-S11 testbox]$

[sand@PS-CNTOS-64-S11 testbox]$ vim t1.c
[sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1
[sand@PS-CNTOS-64-S11 testbox]$ valgrind --tool=memcheck ./t1
==20859== Memcheck, a memory error detector
==20859== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20859== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20859== Command: ./t1
==20859==
==20859== Invalid free() / delete / delete[]
==20859==    at 0x4A05A31: free (vg_replace_malloc.c:325)
==20859==    by 0x4004FF: main (t1.c:8)
==20859==  Address 0x4c26040 is 0 bytes inside a block of size 100 free'd
==20859==    at 0x4A05A31: free (vg_replace_malloc.c:325)
==20859==    by 0x4004F6: main (t1.c:7)
==20859==
==20859==
==20859== HEAP SUMMARY:
==20859==     in use at exit: 0 bytes in 0 blocks
==20859==   total heap usage: 1 allocs, 2 frees, 100 bytes allocated
==20859==
==20859== All heap blocks were freed -- no leaks are possible
==20859==
==20859== For counts of detected and suppressed errors, rerun with: -v
==20859== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
[sand@PS-CNTOS-64-S11 testbox]$

[sand@PS-CNTOS-64-S11 testbox]$ valgrind --tool=memcheck --leak-check=full ./t1
==20899== Memcheck, a memory error detector
==20899== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20899== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20899== Command: ./t1
==20899==
==20899== Invalid free() / delete / delete[]
==20899==    at 0x4A05A31: free (vg_replace_malloc.c:325)
==20899==    by 0x4004FF: main (t1.c:8)
==20899==  Address 0x4c26040 is 0 bytes inside a block of size 100 free'd
==20899==    at 0x4A05A31: free (vg_replace_malloc.c:325)
==20899==    by 0x4004F6: main (t1.c:7)
==20899==
==20899==
==20899== HEAP SUMMARY:
==20899==     in use at exit: 0 bytes in 0 blocks
==20899==   total heap usage: 1 allocs, 2 frees, 100 bytes allocated
==20899==
==20899== All heap blocks were freed -- no leaks are possible
==20899==
==20899== For counts of detected and suppressed errors, rerun with: -v
==20899== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
[sand@PS-CNTOS-64-S11 testbox]$

Une solution possible :

#include<stdio.h>
#include<stdlib.h>

int main()
{
 char *x = malloc(100);
 free(x);
 x=NULL;
 free(x);
 return 0;
}

[sand@PS-CNTOS-64-S11 testbox]$ vim t1.c
[sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1
[sand@PS-CNTOS-64-S11 testbox]$ ./t1
[sand@PS-CNTOS-64-S11 testbox]$

[sand@PS-CNTOS-64-S11 testbox]$ valgrind --tool=memcheck --leak-check=full ./t1
==20958== Memcheck, a memory error detector
==20958== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20958== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20958== Command: ./t1
==20958==
==20958==
==20958== HEAP SUMMARY:
==20958==     in use at exit: 0 bytes in 0 blocks
==20958==   total heap usage: 1 allocs, 1 frees, 100 bytes allocated
==20958==
==20958== All heap blocks were freed -- no leaks are possible
==20958==
==20958== For counts of detected and suppressed errors, rerun with: -v
==20958== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
[sand@PS-CNTOS-64-S11 testbox]$

Consultez le blog sur l'utilisation de Valgrind Lien

0 votes

Mon programme prend environ 30 minutes pour s'exécuter, sur Valgrind il peut prendre 18 à 20 heures pour se terminer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X