Warum bekomme ich einen C -Malloc -Behauptungsversagen?
Frage
Ich implementiere einen Klassifik- und Eroberungspolynomalgorithmus, damit ich ihn gegen eine OpenCL -Implementierung befriedigen kann, aber ich kann nicht bekommen malloc
arbeiten. Wenn ich das Programm ausführe, verteilt es eine Reihe von Sachen, überprüft einige Dinge und sendet dann die size/2
zum Algorithmus. Dann, wenn ich die schlage malloc
Zeile wieder ausspuckt dies:
malloc.c: 3096: malloc_chunk, fd)))) && old_size == 0) || ((nicht signiert lang) (old_size)> = (unsigniert lang) ((((__ __ __ __ __ busingin_offsetof (size_t))) - 1)))) && ((old_top) -> Größe & 0x1) && ((nicht signiert long) old_end & pagemask) == 0) 'fehlgeschlagen. Abgebrochen
Die fragliche 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 einem überprüft fprintf
, und es ist eine positive Ganzzahl (normalerweise 50 zu diesem Zeitpunkt). Ich habe versucht anzurufen malloc
Mit einer einfachen Zahl auch und ich bekomme immer noch den Fehler. Ich bin nur verblüfft darüber, was los ist, und nichts von Google, das ich bisher gefunden habe, ist hilfreich.
Irgendwelche Ideen, was ist los? Ich versuche herauszufinden, wie man ein neueres GCC zusammenstellt, falls es ein Compiler -Fehler ist, aber ich bezweifle es wirklich.
Lösung
99,9% wahrscheinlich, dass Sie das Gedächtnis beschädigt haben (über- oder untergeflüssiges Puffer, schrieb an einen Zeiger, nachdem er befreit wurde, zweimal auf demselben Zeiger usw. frei genannt wurde.)
Führen Sie Ihren Code unter Valgrind Um zu sehen, wo Ihr Programm etwas falsch gemacht hat.
Andere Tipps
Um Ihnen ein besseres Verständnis von zu geben warum Dies passiert, ich möchte auf @R-Samuel-Klatchkos Antwort ein wenig erweitern.
Wenn du anrufst malloc
, Was wirklich passiert, ist etwas komplizierter, als nur ein Stück Erinnerung zu geben, mit dem Sie spielen können. Unter der Haube, malloc
Hält auch einige Haushaltsinformationen über das Gedächtnis, das es Ihnen gegeben hat (vor allem seine Größe), sodass Sie beim Anruf free
, Es weiß Dinge, wie viel Gedächtnis, um frei zu sein. Diese Informationen werden üblicherweise kurz vor dem Speicherort aufbewahrt, der Ihnen von Ihnen 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
Aufbauend darauf (und die Dinge stark vereinfachen), wenn Sie anrufen malloc
, Es muss einen Zeiger auf den nächsten Teil des Speichers bringen, der verfügbar ist. Eine sehr einfache Möglichkeit, dies zu tun size
Bytes weiter unten (oder nach oben) im Speicher. Mit dieser Implementierung sieht Ihr Gedächtnis nach der Zuordnung so etwas aus p1
, p2
und p3
:
+------+----------------+------+--------------------+------+----------+
+ size | | size | | size | +
+------+----------------+------+--------------------+------+----------+
^- p1 ^- p2 ^- p3
Was verursacht also Ihren Fehler?
Stellen Sie sich vor, Ihr Code schreibt fälschlicherweise über die Menge an Speicher, die Sie zugewiesen haben (entweder weil Sie weniger zugewiesen haben als Sie benötigt haben, wie Ihr Problem war oder weil Sie die falschen Grenzbedingungen irgendwo in Ihrem Code verwenden). Sagen Sie, Ihr Code schreibt so viele Daten zu p2
Dass es überschreibt, was sich befindet p3
's size
aufstellen. Wenn Sie jetzt den nächsten Anruf anrufen malloc
, Es wird sich auf den letzten Speicherort ansehen, den es zurückgegeben hat, schauen Sie sich das Feld der Größe an, wechseln Sie zu zu p3 + size
und dann beginnen Sie von dort aus dem Gedächtnis zuzuweisen. Da hat Ihr Code überschrieben size
, Dieser Speicherort erfolgt jedoch nicht mehr nach dem zuvor zugewiesenen Speicher.
Unnötig zu erwähnen, dass das Chaos zerstören kann! Die Implementierer von malloc
haben daher eine Reihe von "Behauptungen" oder Schecks eingerichtet, die versuchen, eine Reihe von geistigen Gesundheit zu überprüfen, um dies (und andere Probleme) zu fangen, wenn sie kurz vor der Tür stehen. In Ihrem speziellen Fall werden diese Behauptungen verletzt und so malloc
Abburns und Ihnen sagen, dass Ihr Code etwas tun würde, um etwas zu tun, das es wirklich nicht tun sollte.
Wie bereits erwähnt, handelt es sich um eine grobe Unvereinbarkeit, aber es reicht aus, um den Punkt zu veranschaulichen. Die GLIBC -Implementierung von malloc
Es ist mehr als 5K -Linien, und es gab erhebliche Untersuchungen darüber, wie gute Mechanismen für dynamische Speicherzuordnungen aufgebaut werden können. Es ist also nicht möglich, alles in einer SO -Antwort abzudecken. Hoffentlich hat dies Ihnen jedoch einen Blick darauf gegeben, was das Problem wirklich verursacht!
Meine alternative Lösung zur Verwendung von Valgrind:
Ich bin sehr glücklich, weil ich nur meinem Freund geholfen habe, ein Programm zu debuggen. Sein Programm hatte genau dieses Problem (malloc()
Abbruch verursachen) mit der gleichen Fehlermeldung von GDB.
Ich habe sein Programm verwendet Adresse Desinfektionsmittel mit
gcc -Wall -g3 -fsanitize=address -o new new.c
^^^^^^^^^^^^^^^^^^
Und rannte dann gdb new
. Wenn das Programm von beendet wird SIGABRT
in einem nachfolgenden Ursachen verursacht malloc()
, Es 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
#0 0x7ffffe49ed19 (/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 is located 0 bytes to the right of 52-byte region [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)
Schauen wir uns die Ausgabe an, insbesondere die Stapelspur:
Der erste Teil besagt, dass es einen ungültigen Schreibvorgang bei new.c:59
. Diese Zeile liest sich
memset(len,0,sizeof(int*)*p);
^^^^^^^^^^^^
Der zweite Teil besagt, dass das Gedächtnis, auf dem das schlechte Schreiben stattgefunden hat new.c:55
. Diese Zeile liest sich
if(!(len=(int*)malloc(sizeof(int)*p))){
^^^^^^^^^^^
Das ist es. Ich brauchte nur weniger als eine halbe Minute, um den Fehler zu finden, der meinen Freund für ein paar Stunden verwirrte. Er hat es geschafft, den Fehler zu finden, aber es ist nachfolgend malloc()
Nennen Sie das fehlgeschlagen, ohne diesen Fehler im vorherigen Code entdecken zu können.
Summe: Versuchen Sie die -fsanitize=address
von GCC oder Klang. Es kann sehr hilfreich sein, wenn Gedächtnisprobleme debuggen.
Sie werden wahrscheinlich irgendwo über das zugewiesene Mem hinaus überrannt. Dann nimmt das zugrunde liegende SW erst auf, wenn Sie Malloc anrufen
Es kann einen Wachwert geben, der von Malloc gefangen wird.
Bearbeiten ... fügte dies für Grenzen hinzu, um Hilfe zu überprüfen
Ich habe die folgende Nachricht erhalten, ähnlich wie Sie:
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)' failed.
Machte einen Fehler, der bei der Verwendung von Malloc eine Methode angerufen hat. Das Multiplikationszeichen '*' mit einem '+' fälschlicherweise überschreibt, wenn der Faktor nach sizeof ()-Bediener beim Hinzufügen eines Feldes zu einem vorzeichenlosen Zeichen-Array aktualisiert wird.
Hier ist der Code, der für den Fehler in meinem Fall 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);
In einer anderen Methode später habe ich Malloc erneut verwendet und die oben gezeigte Fehlermeldung erstellt. Der Anruf war (einfach genug):
UCHAR* b=(UCHAR*)malloc(sizeof(UCHAR)*50);
Denken Sie mit dem '+'-Zeichen beim 1. Aufruf an, der zu Misculus in Kombination mit der sofortigen Initialisierung des Arrays nach dem Abschreiben (Überschreiben, das dem Array nicht zugeordnet wurde), die Verwirrung der MALOC-Speicherkarte mit sich gebracht hat. Deshalb ging der 2. Anruf schief.
Wir haben diesen Fehler bekommen, weil wir vergessen haben, uns mit Sizeof (int) zu multiplizieren. Beachten Sie, dass das Argument für Malloc (..) eine Reihe von Bytes ist, nicht die Anzahl der maschinellen Wörter oder was auch immer.
Ich habe eine Anwendung von Visual C nach GCC über Linux portiert und hatte das gleiche Problem mit
malloc.c: 3096: sysmalloc: Behauptung mit GCC auf Ubuntu 11.
Ich habe den gleichen Code in eine Suse -Verteilung (auf anderen Computer) verschoben und habe kein Problem.
Ich vermute, dass die Probleme nicht in unseren Programmen, sondern in der eigenen LIBC sind.
Ich habe das gleiche Problem bekommen, Malloc habe N wieder in einer Schleife zum Hinzufügen neuer Zeichen für Zeichenfolgen verwendet. Ich hatte das gleiche Problem, aber nachdem ich den zugewiesenen Speicher veröffentlicht hatte void free()
Das Problem wurde sortiert