
Neuromant
Wenn ich mein (C++) Programm starte, stürzt es mit diesem Fehler ab.
* glibc erkannt * ./load: Double Free oder Korruption (!prev): 0x0000000000c6ed50 ***
Wie kann ich dem Fehler auf die Spur kommen?
Ich habe versucht mit print (std::cout
) Aussagen, ohne Erfolg. Könnten gdb
das einfacher machen?
Wenn Sie glibc verwenden, können Sie die MALLOC_CHECK_
Umgebungsvariable zu 2
wird dies dazu führen, dass glibc eine fehlertolerante Version von verwendet malloc
was dazu führt, dass Ihr Programm an dem Punkt abbricht, an dem die doppelte Freigabe erfolgt ist.
Sie können dies von gdb aus festlegen, indem Sie die verwenden set environment MALLOC_CHECK_ 2
Befehl, bevor Sie Ihr Programm ausführen; das Programm sollte abbrechen, mit dem free()
Anruf im Backtrace sichtbar.
siehe die Manpage für malloc()
für mehr Informationen
Es gibt mindestens zwei mögliche Situationen:
- Sie löschen dieselbe Entität zweimal
- Sie löschen etwas, das nicht zugewiesen wurde
Für den ersten empfehle ich dringend, alle gelöschten Zeiger auf NULL zu setzen.
Sie haben drei Möglichkeiten:
- Überladen Sie neue und löschen und verfolgen Sie die Zuordnungen
- Ja, verwenden Sie gdb – dann erhalten Sie einen Backtrace von Ihrem Absturz, und das wird wahrscheinlich sehr hilfreich sein
- wie vorgeschlagen — verwenden Sie Valgrind — es ist nicht einfach, sich darauf einzulassen, aber es wird Ihnen in Zukunft tausendfach Zeit sparen …

Matthäus Flaschen
Sie können gdb verwenden, aber ich würde es zuerst versuchen Valgrind. Siehe die Schnellstartanleitung.
Kurz gesagt, Valgrind instrumentiert Ihr Programm so, dass es verschiedene Arten von Fehlern bei der Verwendung von dynamisch zugewiesenem Speicher erkennen kann, wie z. B. doppelte Freigaben und Schreibvorgänge über das Ende zugewiesener Speicherblöcke hinaus (was den Heap beschädigen kann). Es erkennt und meldet die Fehler sobald sie auftretenwodurch Sie direkt auf die Ursache des Problems hingewiesen werden.

Jack
Drei Grundregeln:
- Zeiger setzen auf
NULL
nach frei
- Prüfen Auf
NULL
vor der Befreiung.
- Zeiger auf initialisieren
NULL
am Anfang.
Die Kombination dieser drei funktioniert ganz gut.

Sandipan Karmakar
Sie können verwenden valgrind
um es zu debuggen.
#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]$
Sehen Sie sich den Blog zur Verwendung von Valgrind an Verknüpfung

Sitesh
Mit modernen C++-Compilern können Sie verwenden Desinfektionsmittel verfolgen.
Musterbeispiel:
Mein Programm:
$cat d_free.cxx
#include<iostream>
using namespace std;
int main()
{
int * i = new int();
delete i;
//i = NULL;
delete i;
}
Mit Adressbereinigungen kompilieren:
# g++-7.1 d_free.cxx -Wall -Werror -fsanitize=address -g
Ausführen :
# ./a.out ========================================== ===================== ==4836==ERROR: AddressSanitizer: Versuch, Double-Free auf 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 befindet sich 0 Byte innerhalb der 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
To learn more about sanitizers you can check this or this or any modern c++ compilers (e.g. gcc, clang etc.) documentations.

user3384414
Are you using smart pointers such as Boost shared_ptr
? If so, check if you are directly using the raw pointer anywhere by calling get()
. I’ve found this to be quite a common problem.
For example, imagine a scenario where a raw pointer is passed (maybe as a callback handler, say) to your code. You might decide to assign this to a smart pointer in order to cope with reference counting etc. Big mistake: your code doesn’t own this pointer unless you take a deep copy. When your code is done with the smart pointer it will destroy it and attempt to destroy the memory it points to since it thinks that no-one else needs it, but the calling code will then try to delete it and you’ll get a double free problem.
Of course, that might not be your problem here. At it’s simplest here’s an example which shows how it can happen. The first delete is fine but the compiler senses that it’s already deleted that memory and causes a problem. That’s why assigning 0 to a pointer immediately after deletion is a good idea.
int main(int argc, char* argv[]) { Zeichen* ptr = neues Zeichen[20]; löschen[] ptr; ptr = 0; // Kommentiere mich aus und sieh zu, wie ich abstürze und brenne. löschen[] ptr; }
Bearbeiten: geändert delete
zu delete[]
da ptr ein Array von char ist.
9865600cookie-checkSo finden Sie einen „Double Free or Corruption“-Fehleryes
Ich frage mich, warum alle das vorschlagen
NULL
Zeiger (was ansonsten abgefangene Fehler maskiert, wie diese Frage schön zeigt), aber niemand schlägt vor, einfach überhaupt keine manuelle Speicherverwaltung durchzuführen, was in C++ sehr gut möglich ist. Ich habe nicht geschriebendelete
in Jahren. (Und ja, mein Code ist leistungskritisch. Sonst wäre er nicht in C++ geschrieben worden.)– sbi
25. Mai 2010 um 8:32 Uhr
@sbi: Haufenkorruption und ähnliches werden selten erwischt, zumindest nicht dort, wo sie passieren.
NULL
ing-Zeiger könnten Ihr Programm früher zum Absturz bringen.– Hasturkun
25. Mai 2010 um 8:45 Uhr
@Hasturkun: Dem stimme ich absolut nicht zu. Ein großer Ansporn dazu
NULL
Zeiger ist ein zweites zu verhinderndelete ptr;
vor der Explosion – was einen Fehler maskiert, denn diese Sekundedelete
hätte nie passieren dürfen. (Es wird auch verwendet, um zu prüfen, ob ein Zeiger immer noch auf ein gültiges Objekt zeigt. Aber das wirft nur die Frage auf, warum Sie einen Zeiger im Gültigkeitsbereich haben, der kein Objekt hat, auf das er zeigen kann.)– sbi
25. Mai 2010 um 8:55 Uhr
Ich denke, alle Antworten unten, die darauf hindeuten, “manuell” nach Zeigerproblemen zu suchen und sie auf Null zu setzen usw., sind schlechte Pflaster. Es ist von unschätzbarem Wert, zu lernen, wie man eines der echten Werkzeuge verwendet, um diese Probleme zu finden. Im Fall von Valgrind kann es so einfach sein wie apt-get install valgrind und Ihrem Programm valgrind und eine Option voranzustellen (wie eine der Antworten unten zeigt).
– Björn W
22. April 2021 um 16:16 Uhr