Warum erhalte ich einen C-malloc-Assertion-Fehler?

Lesezeit: 9 Minuten

Benutzeravatar von Chris
Chris

Ich implementiere einen Polynom-Algorithmus zum Teilen und Erobern, damit ich ihn mit einer OpenCL-Implementierung vergleichen kann, aber ich kann es nicht bekommen malloc arbeiten. Wenn ich das Programm starte, weist es eine Menge Zeug zu, überprüft einige Dinge und sendet dann die size/2 zum Algorithmus. Dann, als ich die traf malloc Zeile wieder spuckt es das aus:

malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted

Die betreffende Zeile lautet:

int *mult(int size, int *a, int *b) {
    int *out,i, j, *tmp1, *tmp2, *tmp3, *tmpa1, *tmpa2, *tmpb1, *tmpb2,d, *res1, *res2;
    fprintf(stdout, "size: %d\n", size);

    out = (int *)malloc(sizeof(int) * size * 2);
}

Ich habe die Größe mit a überprüft fprintf, und es ist eine positive Ganzzahl (an diesem Punkt normalerweise 50). Ich habe versucht anzurufen malloc auch mit einer einfachen Nummer und ich bekomme immer noch den Fehler. Ich bin nur ratlos, was los ist, und nichts von Google, das ich bisher gefunden habe, ist hilfreich.

Irgendwelche Ideen, was los ist? Ich versuche herauszufinden, wie man einen neueren GCC kompiliert, falls es sich um einen Compilerfehler handelt, aber ich bezweifle es wirklich.

  • Ich vermute, dass das Problem tatsächlich eine Zeile davor ist. Vielleicht ein Doppel frei?

    – Mitch Weizen

    7. Juni 2010 um 5:21 Uhr

  • 3. Zeile im Programm: int *mult(int size, int *a, int *b) { int *out,i, j, *tmp1, *tmp2, *tmp3, *tmpa1, *tmpa2, *tmpb1, *tmpb2 ,d, *res1, *res2; fprintf(stdout, “Größe: %d\n”, Größe); out = (int *)malloc(sizeof(int) * size * 2);

    – Chris

    7. Juni 2010 um 5:22 Uhr


99,9 % Wahrscheinlichkeit, dass Sie einen beschädigten Speicher haben (einen Puffer über- oder unterlaufen lassen, in einen Zeiger geschrieben haben, nachdem er freigegeben wurde, free zweimal auf demselben Zeiger aufgerufen haben usw.)

Führen Sie Ihren Code unter aus Valgrind um zu sehen, wo Ihr Programm etwas falsch gemacht hat.

  • Fest. Valgrind hat definitiv geholfen. Ich habe meinen alten Matlab-Code falsch transkribiert und hatte eine for-Schleife, die über j iterierte, dann machte es j++, was das Array, auf das es schrieb, am meisten überschrieb und irgendwie dazu führte, dass malloc fehlschlug. danke für die Hilfe!

    – Chris

    7. Juni 2010 um 5:52 Uhr

  • Valgrind war genau das Werkzeug, das ich brauchte, um herauszufinden, was los war, als ich diesen Fehler bekam. Danke für die Erwähnung.

    – Alexwells

    31. Dezember 2012 um 18:05 Uhr

  • Sehen Sie sich meine Antwort unten für eine Lösung mit Address Sanitizer für eine einfachere Verwendung und eine bessere Anleitung / Illustration an.

    – iBug

    11. April 2021 um 13:33 Uhr

Zum besseren Verständnis warum In diesem Fall möchte ich die Antwort von @ r-samuel-klatchko ein wenig erweitern.

Wenn du anrufst malloc, was wirklich passiert, ist etwas komplizierter, als Ihnen nur einen Teil des Speichers zum Spielen zu geben. Unter der Haube, malloc speichert auch einige Verwaltungsinformationen über den Speicher, den es Ihnen gegeben hat (am wichtigsten, seine Größe), damit Sie es bei Ihrem Anruf verwenden können free, weiß es Dinge wie wie viel Speicher freizugeben ist. Diese Informationen werden normalerweise direkt vor dem Speicherort gespeichert, der Ihnen von zurückgegeben wird malloc. Ausführlichere Informationen finden Sie im Internet™aber die (sehr) Grundidee ist ungefähr so:

+------+-------------------------------------------------+
+ size |                  malloc'd memory                +
+------+-------------------------------------------------+
       ^-- location in pointer returned by malloc

Darauf aufbauend (und vieles vereinfachend), wenn Sie anrufen malloc, muss es einen Zeiger auf den nächsten verfügbaren Teil des Speichers erhalten. Eine sehr einfache Möglichkeit, dies zu tun, besteht darin, sich das vorherige Stück Speicher anzusehen, das es verschenkt hat, und sich zu bewegen size Bytes weiter unten (oder oben) im Speicher. Mit dieser Implementierung sieht Ihr Speicher nach der Zuweisung ungefähr so ​​​​aus p1, p2 und p3:

+------+----------------+------+--------------------+------+----------+
+ size |                | size |                    | size |          +
+------+----------------+------+--------------------+------+----------+
       ^- p1                   ^- p2                       ^- p3

Also, was verursacht deinen Fehler?

Nun, stellen Sie sich vor, Ihr Code schreibt fälschlicherweise über die Menge an Speicher hinaus, die Sie zugewiesen haben (entweder weil Sie weniger als nötig zugewiesen haben, wie es Ihr Problem war, oder weil Sie irgendwo in Ihrem Code die falschen Randbedingungen verwenden). Angenommen, Ihr Code schreibt so viele Daten zu p2 dass es anfängt zu überschreiben, was drin ist p3‘s size aufstellen. Wenn Sie jetzt das nächste Mal anrufen mallocwird es sich den letzten Speicherort ansehen, den es zurückgegeben hat, sich sein Größenfeld ansehen und zu ihm wechseln p3 + size und beginnen Sie dann mit der Speicherzuweisung von dort aus. Da dein Code überschrieben wurde sizejedoch ist dieser Speicherplatz nicht mehr hinter dem zuvor allokierten Speicher.

Unnötig zu erwähnen, dass dies Chaos anrichten kann! Die Implementierer von malloc haben daher eine Reihe von “Behauptungen” oder Überprüfungen vorgenommen, die versuchen, eine Reihe von Plausibilitätsprüfungen durchzuführen, um dies (und andere Probleme) zu erkennen, wenn sie auftreten. In Ihrem speziellen Fall werden diese Behauptungen verletzt, und somit malloc bricht ab und teilt Ihnen mit, dass Ihr Code im Begriff war, etwas zu tun, was er wirklich nicht tun sollte.

Wie bereits erwähnt, ist dies eine grobe Vereinfachung, aber es reicht aus, um den Punkt zu veranschaulichen. Die glibc-Implementierung von malloc ist mehr als 5.000 Zeilen, und es wurden umfangreiche Untersuchungen zum Aufbau guter dynamischer Speicherzuweisungsmechanismen durchgeführt, sodass es nicht möglich ist, alles in einer SO-Antwort abzudecken. Hoffentlich hat Ihnen dies einen kleinen Einblick gegeben, was das Problem wirklich verursacht!

  • Es ist wirklich hilfreich!

    – H. Potter

    19. August 2021 um 2:49 Uhr

Benutzeravatar von iBug
iBug

Meine alternative Lösung zur Verwendung von Valgrind:

Ich bin sehr glücklich, weil ich gerade meinem Freund geholfen habe, ein Programm zu debuggen. Sein Programm hatte genau dieses Problem (malloc() verursacht Abbruch), mit der gleichen Fehlermeldung von GDB.

Ich habe sein Programm mit kompiliert Adresse Sanitizer mit

gcc -Wall -g3 -fsanitize=address -o new new.c
              ^^^^^^^^^^^^^^^^^^

Und dann rannte gdb new. Wenn das Programm beendet wird durch SIGABRT in einer Folge verursacht malloc()werden viele nützliche Informationen gedruckt:

=============================================== =============== ==407==ERROR: AddressSanitizer: Heap-Buffer-Overflow on address 0x6060000000b4 at pc 0x7ffffe49ed1a bp 0x7ffffffedc20 sp 0x7ffffffed3c8 WRITE of size 104 at 0x6060000000b4 thread T0 #19.0 4.0 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5ed19) #1 0x8001dab in CreatHT2 /home/wsl/Desktop/hash/new.c:59 #2 0x80031cf in main /home/wsl/Desktop /hash/new.c:209 #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) #4 0x8001679 in _start (/mnt/d/Desktop/hash/new+0x1679) 0x6060000000b4 befindet sich 0 Bytes rechts vom 52-Byte-Bereich [0x606000000080,0x6060000000b4)
allocated by thread T0 here:
    #0 0x7ffffe51eb50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50)
    #1 0x8001d56 in CreatHT2 /home/wsl/Desktop/hash/new.c:55
    #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209
    #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)

Let’s take a look at the output, especially the stack trace:

The first part says there’s a invalid write operation at new.c:59. That line reads

memset(len,0,sizeof(int*)*p);
             ^^^^^^^^^^^^

The second part says the memory that the bad write happened on is created at new.c:55. That line reads

if(!(len=(int*)malloc(sizeof(int)*p))){
                      ^^^^^^^^^^^

That’s it. It only took me less than half a minute to locate the bug that confused my friend for a few hours. He managed to locate the failure, but it’s a subsequent malloc() call that failed, without being able to spot this error in previous code.

Sum up: Try the -fsanitize=address of GCC or Clang. It can be very helpful when debugging memory issues.

  • You just saved my life.

    – Nate Symer

    Apr 8, 2020 at 0:50

  • Nice alternative… I was searching for a bug in my code for about two hours, and with this I have found it and fixed it in about 10 minutes (just a parenthesis).

    – Daniel Carrasco Marín

    Aug 16, 2021 at 14:39


pbernatchez's user avatar
pbernatchez

You are probably overrunning beyond the allocated mem somewhere.
then the underlying sw doesn’t pick up on it until you call malloc

There may be a guard value clobbered that is being caught by malloc.

edit…added this for bounds checking help

http://www.lrde.epita.fr/~akim/ccmp/doc/bounds-checking.html

Michael Grieswald's user avatar
Michael Grieswald

I got the following message, similar to your one:


    program: malloc.c:2372: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) ||  ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1)) & ~((2 *(sizeof (size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long) old_end & pagemask) == 0)' fehlgeschlagen.

Vor einigen Methodenaufrufen einen Fehler gemacht, als malloc verwendet wurde. Das Multiplikationszeichen ‘*’ wurde fälschlicherweise mit einem ‘+’ überschrieben, wenn der Faktor nach dem sizeof()-Operator beim Hinzufügen eines Feldes zu einem unsigned char-Array aktualisiert wurde.

Hier ist der Code, der in meinem Fall für den Fehler verantwortlich ist:


    UCHAR* b=(UCHAR*)malloc(sizeof(UCHAR)+5);
    b[INTBITS]=(some calculation);
    b[BUFSPC]=(some calculation);
    b[BUFOVR]=(some calculation);
    b[BUFMEM]=(some calculation);
    b[MATCHBITS]=(some calculation);

Später habe ich in einer anderen Methode malloc erneut verwendet und es hat die oben gezeigte Fehlermeldung erzeugt. Der Aufruf war (einfach genug):


    UCHAR* b=(UCHAR*)malloc(sizeof(UCHAR)*50);

Denken Sie daran, dass die Verwendung des ‘+’-Zeichens beim 1. Aufruf, die zu Fehlkalkülen in Kombination mit der sofortigen Initialisierung des Arrays danach führte (Überschreiben von Speicher, der dem Array nicht zugewiesen war), etwas Verwirrung in die Speicherzuordnung von malloc gebracht hat. Daher ging der 2. Anruf schief.

Benutzeravatar von Phob
Phob

Wir haben diesen Fehler erhalten, weil wir vergessen haben, mit sizeof(int) zu multiplizieren. Beachten Sie, dass das Argument von malloc(..) eine Anzahl von Bytes ist, nicht die Anzahl von Maschinenwörtern oder was auch immer.

Benutzeravatar von namila007
namila007

Ich habe das gleiche Problem, ich habe malloc über n immer wieder in einer Schleife verwendet, um neue char * string-Daten hinzuzufügen. Ich hatte das gleiche Problem, aber nachdem ich den zugewiesenen Speicher freigegeben hatte void free() Problem wurden sortiert

1421800cookie-checkWarum erhalte ich einen C-malloc-Assertion-Fehler?

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

Privacy policy