Wenn ich mein (C ++) Programm ausführe, stürzt es mit diesem Fehler ab.
* glibc erkannt * ./load: doppelt frei oder beschädigt (! prev): 0x0000000000c6ed50 ***
Wie kann ich den Fehler aufspüren?
Ich habe versucht, print ( std::cout
) -Anweisungen zu verwenden, ohne Erfolg. Könnte gdb
das einfacher machen?
NULL
Zeiger vorschlägt (die Fehler maskieren, die sonst abgefangen werden, wie diese Frage gut zeigt), aber niemand schlägt vor, einfach überhaupt keine manuelle Speicherverwaltung durchzuführen, was in C ++ sehr gut möglich ist. Ich habe seit Jahren nicht mehr geschriebendelete
. (Und ja, mein Code ist leistungskritisch. Sonst wäre er nicht in C ++ geschrieben worden.)NULL
Zeiger können dazu führen, dass Ihr Programm früher abstürzt.NULL
Zeiger besteht darin, zu verhindern, dass eine Sekundedelete ptr;
explodiert - was einen Fehler maskiert, da diese Sekundedelete
niemals hätte passieren dürfen. (Es wird auch verwendet, um zu überprüfen, ob ein Zeiger noch auf ein gültiges Objekt zeigt. Dies wirft jedoch nur die Frage auf, warum Sie einen Zeiger im Gültigkeitsbereich haben, auf den kein Objekt verweisen kann.)Antworten:
Wenn Sie glibc verwenden, können Sie die
MALLOC_CHECK_
Umgebungsvariable auf setzen2
. Dies führt dazu, dass glibc eine fehlertolerante Version von verwendetmalloc
, wodurch Ihr Programm an dem Punkt abgebrochen wird, an dem das Double Free ausgeführt wird.Sie können dies über gdb festlegen, indem Sie den
set environment MALLOC_CHECK_ 2
Befehl verwenden, bevor Sie Ihr Programm ausführen. Das Programm sollte abgebrochen werden, wobei derfree()
Aufruf im Backtrace sichtbar ist.Weitere Informationen finden Sie in der Manpage
malloc()
quelle
MALLOC_CHECK_2
tatsächlich mein doppeltes freies Problem (obwohl es nicht behoben wird, wenn es nur im Debug-Modus ist)Es gibt mindestens zwei mögliche Situationen:
Für den ersten empfehle ich dringend, alle gelöschten Zeiger auf NULL zu setzen.
Sie haben drei Möglichkeiten:
quelle
Sie können gdb verwenden, aber ich würde zuerst Valgrind versuchen . Siehe die Kurzanleitung .
Kurz gesagt, Valgrind instrumentiert Ihr Programm so, dass es verschiedene Arten von Fehlern bei der Verwendung von dynamisch zugewiesenem Speicher erkennen kann, z. B. doppelte Freigaben und Schreibvorgänge nach dem Ende der zugewiesenen Speicherblöcke (die den Heap beschädigen können). Es erkennt und meldet die Fehler , sobald sie auftreten , und weist Sie so direkt auf die Ursache des Problems hin.
quelle
Drei Grundregeln:
NULL
nach frei setzenNULL
bevor Sie zu befreien.NULL
Beginn.Die Kombination dieser drei funktioniert ganz gut.
quelle
Sie können es
valgrind
zum Debuggen verwenden.#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]$
Eine mögliche Lösung:
#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]$
Lesen Sie den Blog über die Verwendung von Valgrind Link
quelle
Mit modernen C ++ - Compilern können Sie Desinfektionsmittel verwenden, um zu verfolgen.
Beispielbeispiel:
Mein Programm:
$cat d_free.cxx #include<iostream> using namespace std; int main() { int * i = new int(); delete i; //i = NULL; delete i; }
Kompilieren Sie mit Adressdesinfektionsmitteln:
# g++-7.1 d_free.cxx -Wall -Werror -fsanitize=address -g
Ausführen :
# ./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
Um mehr über Desinfektionsmittel zu erfahren, können Sie diese oder jene oder alle modernen C ++ - Compiler-Dokumentationen (z. B. gcc, clang usw.) überprüfen .
quelle
Verwenden Sie intelligente Zeiger wie Boost
shared_ptr
? Wenn ja, überprüfen Sie durch Aufrufen, ob Sie den Rohzeiger irgendwo direkt verwendenget()
. Ich habe festgestellt, dass dies ein recht häufiges Problem ist.Stellen Sie sich beispielsweise ein Szenario vor, in dem ein Rohzeiger (z. B. als Callback-Handler) an Ihren Code übergeben wird. Sie können dies einem intelligenten Zeiger zuweisen, um mit der Referenzzählung usw. fertig zu werden. Großer Fehler: Ihr Code besitzt diesen Zeiger nur, wenn Sie eine tiefe Kopie erstellen. Wenn Ihr Code mit dem Smart Pointer fertig ist, wird er zerstört und versucht, den Speicher zu zerstören, auf den er verweist, da er denkt, dass niemand anderes ihn benötigt, aber der aufrufende Code versucht dann, ihn zu löschen, und Sie erhalten ein Double freies Problem.
Das könnte hier natürlich nicht Ihr Problem sein. Am einfachsten ist hier ein Beispiel, das zeigt, wie es passieren kann. Das erste Löschen ist in Ordnung, aber der Compiler erkennt, dass dieser Speicher bereits gelöscht wurde, und verursacht ein Problem. Aus diesem Grund ist es eine gute Idee, einem Zeiger unmittelbar nach dem Löschen 0 zuzuweisen.
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; }
Bearbeiten: geändert
delete
indelete[]
, da ptr ein Array von Zeichen ist.quelle
Ich weiß, dass dies ein sehr alter Thread ist, aber es ist die häufigste Google-Suche nach diesem Fehler, und in keiner der Antworten wird eine häufige Fehlerursache erwähnt.
Welches ist das Schließen einer Datei, die Sie bereits geschlossen haben.
Wenn Sie nicht aufpassen und zwei verschiedene Funktionen dieselbe Datei schließen, generiert die zweite diesen Fehler.
quelle