So finden Sie einen „Double Free or Corruption“-Fehler

Lesezeit: 12 Minuten

So finden Sie einen „Double Free or Corruption Fehler
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?

  • 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 geschrieben delete 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. NULLing-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 verhindern delete ptr; vor der Explosion – was einen Fehler maskiert, denn diese Sekunde delete 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

Wenn Sie glibc verwenden, können Sie die MALLOC_CHECK_ Umgebungsvariable zu 2wird dies dazu führen, dass glibc eine fehlertolerante Version von verwendet mallocwas 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

  • Einstellung MALLOC_CHECK_2 tatsächlich mein Double-Free-Problem behoben (obwohl es nicht behoben wird, wenn es nur im Debug-Modus ist)

    – puck

    18. Januar 2019 um 6:30 Uhr

  • @puk Ich habe das gleiche Problem, das Setzen von MALLOC_CHECK_ auf 2 vermeidet mein Double-Free-Problem. Welche anderen Optionen gibt es, um weniger Code einzufügen, um das Problem zu reproduzieren und einen Backtrace bereitzustellen?

    – Wei Zhong

    2. April 2019 um 5:30 Uhr

  • Haben Sie es auch, wo das Setzen von MALLOC_CHECK_ das Problem vermeidet. Mitkommentatoren / irgendjemand … haben Sie einen anderen Weg gefunden, um das Problem zu zeigen?

    – Durchsichtiger Coder

    27. Oktober 2020 um 17:10 Uhr


  • ” Wenn MALLOC_CHECK_ auf einen Wert ungleich Null gesetzt ist, wird eine spezielle (weniger effiziente) Implementierung verwendet, die tolerant gegenüber einfachen Fehlern ist, wie z. B. doppelte Aufrufe von free mit demselben Argument oder Überläufe eines einzelnen Bytes (off -by-one Fehler).” gnu.org/software/libc/manual/html_node/… Es scheint also, als würde MALLOC_CHECK_ nur verwendet, um einfache Speicherfehler zu vermeiden, nicht um sie zu erkennen.

    – Durchsichtiger Coder

    27. Oktober 2020 um 17:14 Uhr

  • Tatsächlich…. support.microfocus.com/kb/doc.php?id=3113982 Es scheint, als wäre das Setzen von MALLOC_CHECK_ auf 3 am nützlichsten und kann verwendet werden, um Fehler zu erkennen.

    – Durchsichtiger Coder

    27. Oktober 2020 um 17:22 Uhr

Es gibt mindestens zwei mögliche Situationen:

  1. Sie löschen dieselbe Entität zweimal
  2. 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:

  1. Überladen Sie neue und löschen und verfolgen Sie die Zuordnungen
  2. Ja, verwenden Sie gdb – dann erhalten Sie einen Backtrace von Ihrem Absturz, und das wird wahrscheinlich sehr hilfreich sein
  3. wie vorgeschlagen — verwenden Sie Valgrind — es ist nicht einfach, sich darauf einzulassen, aber es wird Ihnen in Zukunft tausendfach Zeit sparen …

  • 2. würde eine Beschädigung verursachen, aber ich glaube nicht, dass diese Meldung im Allgemeinen erscheinen würde, da die Plausibilitätsprüfung nur auf dem Heap durchgeführt wird. Ich denke jedoch, dass 3. ein Heap-Pufferüberlauf möglich ist.

    – Matthäus Flaschen

    25. Mai 2010 um 5:31 Uhr

  • Gut. Richtig, ich habe es versäumt, den Zeiger auf NULL zu setzen, und bin mit diesem Fehler konfrontiert. Stunden gelernt!

    – Hrushi

    27. Februar 2017 um 3:05 Uhr

1646892608 967 So finden Sie einen „Double Free or Corruption Fehler
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.

  • @SMR, in diesem Fall sind die wesentlichen Teile der Antwort die gesamte, große, verlinkte Seite. Es ist also vollkommen in Ordnung, nur den Link in die Antwort aufzunehmen. Ein paar Worte darüber, warum der Autor Valgrind gegenüber gdb bevorzugt und wie er das angehen würde Spezifisch Problem ist IMHO, was wirklich in der Antwort fehlt.

    – ndemou

    17. Mai 2016 um 7:16 Uhr

  • Man kann auch lldb verwenden, wenn man llvm gegenüber gnu bevorzugt.

    – Nikita Demodow

    6. Juni 2021 um 16:57 Uhr

  • Für mich bestand der Fehler darin, dass der Speicher einem Zeiger freigegeben wurde, der korrekt eingerichtet war (nicht NULL) und der korrekt freigegeben wurde – nur einmal und nicht zweimal … Valgrind zeigte, dass einem anderen Zeiger die falsche Menge an Speicher zugewiesen wurde. ., was zu obiger Fehlermeldung führte… – falsche Zuordnung für einen ganz anderen Pointer behoben und Problem gelöst. vielen dank für die hilfreiche antwort 🙂

    – tom

    27. Oktober 2021 um 23:56 Uhr

1646892608 664 So finden Sie einen „Double Free or Corruption Fehler
Jack

Drei Grundregeln:

  1. Zeiger setzen auf NULL nach frei
  2. Prüfen Auf NULL vor der Befreiung.
  3. Zeiger auf initialisieren NULL am Anfang.

Die Kombination dieser drei funktioniert ganz gut.

1646892609 553 So finden Sie einen „Double Free or Corruption Fehler
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

  • Mein Programm dauert etwa 30 Minuten, auf Valgrind kann es 18 bis 20 Stunden dauern, bis es fertig ist.

    – Kemin Zhou

    3. April 2019 um 21:31 Uhr

So finden Sie einen „Double Free or Corruption Fehler
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.

  • My program takes about 30 minutes to run, on Valgrind it can take 18 to 20 hours to finish.

    – Kemin Zhou

    Apr 3, 2019 at 21:31

1646892609 279 So finden Sie einen „Double Free or Corruption Fehler
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.

  • Ich habe in meinem Programm keine Löschbefehle verwendet. Kann das immer noch das Problem sein?

    – Neuromant

    26. Mai 2010 um 1:57 Uhr

  • @Phenom: Warum hast du keine Löschungen verwendet? Liegt es daran, dass Sie intelligente Zeiger verwenden? Vermutlich verwenden Sie new in Ihrem Code, um Objekte auf dem Heap zu erstellen? Wenn die Antwort auf beide Fragen ja lautet, verwenden Sie dann get / set für die intelligenten Zeiger, um rohe Zeiger zu kopieren? Wenn ja, nicht! Sie würden die Referenzzählung brechen. Alternativ könnten Sie einen Zeiger aus dem Bibliothekscode, den Sie aufrufen, einem intelligenten Zeiger zuweisen. Wenn Sie den Speicher, auf den gezeigt wird, nicht “besitzen”, dann tun Sie es nicht, da sowohl die Bibliothek als auch der intelligente Zeiger versuchen werden, ihn zu löschen.

    – Komponente 10

    27. Mai 2010 um 11:23 Uhr

986560cookie-checkSo finden Sie einen „Double Free or Corruption“-Fehler

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy