Lorsque j'exécute mon programme (C ++), il se bloque avec cette erreur.
* glibc détecté * ./load: double libre ou corruption (! prev): 0x0000000000c6ed50 ***
Comment puis-je retrouver l'erreur?
J'ai essayé d'utiliser les std::cout
instructions print ( ), sans succès. Pourrait gdb
rendre cela plus facile?
NULL
pointeurs (qui masquent les erreurs qui sont autrement capturées, comme le montre bien cette question), mais personne ne suggère de ne pas faire du tout de gestion manuelle de la mémoire, ce qui est très bien possible en C ++. Je n'ai pas écritdelete
depuis des années. (Et, oui, mon code est critique pour les performances. Sinon, il n'aurait pas été écrit en C ++.)NULL
des pointeurs peuvent faire planter votre programme plus tôt.NULL
pointeurs est d'empêcher une secondedelete ptr;
d'exploser - ce qui masque une erreur, car cette secondedelete
n'aurait jamais dû se produire. (Il est également utilisé pour vérifier si un pointeur pointe toujours vers un objet valide. Mais cela soulève simplement la question de savoir pourquoi vous avez un pointeur dans la portée qui n'a pas d'objet versRéponses:
Si vous utilisez la glibc, vous pouvez définir la
MALLOC_CHECK_
variable d'environnement sur2
, cela obligera la glibc à utiliser une version tolérante aux erreurs demalloc
, ce qui entraînera l'abandon de votre programme au moment où le double free est effectué.Vous pouvez définir cela à partir de gdb en utilisant la
set environment MALLOC_CHECK_ 2
commande avant d'exécuter votre programme; le programme doit abandonner, l'free()
appel étant visible dans la trace arrière.voir la page de manuel
malloc()
pour plus d'informationsla source
MALLOC_CHECK_2
fait résolu mon problème de double gratuit (bien qu'il ne soit pas résolu s'il est en mode débogage uniquement)Il existe au moins deux situations possibles:
Pour le premier, je suggère fortement NULL-ing tous les pointeurs supprimés.
Vous avez trois options:
la source
Vous pouvez utiliser gdb, mais j'essaierais d'abord Valgrind . Consultez le guide de démarrage rapide .
En bref, Valgrind instrumente votre programme afin qu'il puisse 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'elles se produisent , vous indiquant ainsi directement la cause du problème.
la source
Trois règles de base:
NULL
après libreNULL
avant de libérer.NULL
début.La combinaison de ces trois fonctionne assez bien.
la source
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 Link
la source
Avec les compilateurs C ++ modernes, vous pouvez utiliser des désinfectants pour effectuer le suivi.
Exemple d'exemple:
Mon programme:
$cat d_free.cxx #include<iostream> using namespace std; int main() { int * i = new int(); delete i; //i = NULL; delete i; }
Compilez avec des désinfectants d'adresse:
# g++-7.1 d_free.cxx -Wall -Werror -fsanitize=address -g
Exécutez:
# ./a.out ================================================================= ==4836==ERROR: AddressSanitizer: attempting double-free on 0x602000000010 in thread T0: #0 0x7f35b2d7b3c8 in operator delete(void*, unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140 #1 0x400b2c in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:11 #2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04) #3 0x400a08 (/media/sf_shared/jkr/cpp/d_free/a.out+0x400a08) 0x602000000010 is located 0 bytes inside of 4-byte region [0x602000000010,0x602000000014) freed by thread T0 here: #0 0x7f35b2d7b3c8 in operator delete(void*, unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140 #1 0x400b1b in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:9 #2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04) previously allocated by thread T0 here: #0 0x7f35b2d7a040 in operator new(unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:80 #1 0x400ac9 in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:8 #2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04) SUMMARY: AddressSanitizer: double-free /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140 in operator delete(void*, unsigned long) ==4836==ABORTING
Pour en savoir plus sur les désinfectants, vous pouvez vérifier ceci ou cela ou n'importe quelle documentation des compilateurs C ++ modernes (par exemple gcc, clang etc.).
la source
Utilisez-vous des pointeurs intelligents tels que Boost
shared_ptr
? Si tel est le cas, vérifiez si vous utilisez directement le pointeur brut n'importe où en appelantget()
. J'ai trouvé que c'était un problème assez courant.Par exemple, imaginez un scénario dans lequel un pointeur brut est passé (peut-être en tant que gestionnaire de rappel, par exemple) à votre code. Vous pourriez décider de l'attribuer à un pointeur intelligent afin de faire face au comptage de références, etc. Grosse erreur: votre code ne possède pas ce pointeur à moins que vous n'en preniez une copie complète. Lorsque votre code est terminé avec le pointeur intelligent, il le détruira et tentera de détruire la mémoire vers laquelle il pointe car il pense que personne d'autre n'en a besoin, mais le code appelant essaiera alors de le supprimer et vous obtiendrez un double problème gratuit.
Bien sûr, ce n'est peut-être pas votre problème ici. Au plus simple, voici un exemple qui montre comment cela peut arriver. La première suppression est correcte, mais le compilateur détecte qu'elle est déjà supprimée de cette mémoire et pose un problème. C'est pourquoi attribuer 0 à un pointeur immédiatement après la suppression est une bonne idée.
int main(int argc, char* argv[]) { char* ptr = new char[20]; delete[] ptr; ptr = 0; // Comment me out and watch me crash and burn. delete[] ptr; }
Edit: changé
delete
endelete[]
, car ptr est un tableau de char.la source
Je sais qu'il s'agit d'un fil de discussion très ancien, mais il s'agit de la principale recherche sur Google pour cette erreur, et aucune des réponses ne mentionne une cause commune de l'erreur.
Ce qui ferme un fichier que vous avez déjà fermé.
Si vous ne faites pas attention et que deux fonctions différentes ferment le même fichier, la seconde générera cette erreur.
la source