Ich implementiere einen Divide and Conquer-Polynomalgorithmus, damit ich ihn mit einer OpenCL-Implementierung vergleichen kann, aber ich kann nicht malloc
arbeiten. Wenn ich das Programm ausführe, ordnet es eine Menge Dinge zu, überprüft einige Dinge und sendet sie dann size/2
an den Algorithmus. Wenn ich dann wieder auf die malloc
Linie treffe, spuckt es Folgendes 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 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 a überprüft fprintf
und es ist eine positive ganze Zahl (normalerweise 50 zu diesem Zeitpunkt). Ich habe versucht, auch malloc
mit einer einfachen Nummer anzurufen, und es wird immer noch der Fehler angezeigt. Ich bin nur ratlos darüber, was los ist, und nichts von Google, was ich bisher gefunden habe, ist hilfreich.
Irgendwelche Ideen, was los ist? Ich versuche herauszufinden, wie ein neueres GCC kompiliert werden kann, falls es sich um einen Compilerfehler handelt, aber ich bezweifle es wirklich.
Antworten:
99,9% wahrscheinlich, dass Sie den Speicher beschädigt haben (ein Puffer ist über- oder untergelaufen, wurde nach dem Freigeben in einen Zeiger geschrieben, zweimal mit demselben Zeiger als frei bezeichnet usw.)
Führen Sie Ihren Code unter Valgrind aus , um festzustellen , wo Ihr Programm etwas falsch gemacht hat.
quelle
Um Ihnen ein besseres Verständnis dafür zu geben, warum dies geschieht, möchte ich die Antwort von @ r-samuel-klatchko etwas näher erläutern.
Wenn Sie anrufen
malloc
, ist das, was wirklich passiert, etwas komplizierter, als Ihnen nur einen Teil des Gedächtnisses zum Spielen zu geben. Unter der Haube werdenmalloc
auch einige Haushaltsinformationen über den Speicher gespeichert, den Sie erhalten haben (vor allem über die Größe), sodass er beim Anrufen beispielsweisefree
weiß, wie viel Speicher freigegeben werden muss. Diese Informationen werden normalerweise direkt vor dem Speicherort gespeichert, den Sie von erhalten habenmalloc
. 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 die Dinge stark vereinfachend) muss beim Aufrufen
malloc
ein Zeiger auf den nächsten verfügbaren Teil des Speichers abgerufen werden. Eine sehr einfache Möglichkeit, dies zu tun, besteht darin, das zuvor verschenkte Speicherbit zu betrachten und diesize
Bytes im Speicher weiter nach unten (oder oben) zu verschieben. Mit dieser Implementierung, beenden Sie mit Ihrem Gedächtnis auf etwas so aussehen , nachdem die Zuweisungp1
,p2
undp3
:Was verursacht Ihren Fehler?
Stellen Sie sich vor, Ihr Code schreibt fälschlicherweise über die von Ihnen zugewiesene Speichermenge hinaus (entweder weil Sie weniger zugewiesen haben, als Sie als Problem benötigt haben, oder weil Sie irgendwo in Ihrem Code die falschen Randbedingungen verwenden). Sagen Sie den Code schreibt so viele Daten ,
p2
dass es beginnt zu überschreiben , was in istp3
‚ssize
Feld. Wenn Sie jetzt das nächste Mal anrufenmalloc
, wird der zuletzt zurückgegebene Speicherort angezeigt, das Größenfeld angezeigt, derp3 + size
Speicherplatz verschoben und von dort aus mit der Zuweisung von Speicher begonnen. Da Ihr Code jedoch überschriebensize
wurde, befindet sich dieser Speicherort nicht mehr hinter dem zuvor zugewiesenen Speicher.Unnötig zu sagen, dass dies Chaos zerstören kann! Die Implementierer von
malloc
haben daher eine Reihe von "Behauptungen" oder Überprüfungen abgegeben, die versuchen, eine Reihe von Überprüfungen der geistigen Gesundheit durchzuführen, um dies (und andere Probleme) zu erkennen, wenn sie in Kürze eintreten. In Ihrem speziellen Fall werden diese Behauptungen verletzt und dahermalloc
abgebrochen, um Ihnen mitzuteilen, dass Ihr Code etwas tun würde, was er eigentlich nicht tun sollte.Wie bereits erwähnt, handelt es sich um eine grobe Vereinfachung, die jedoch ausreicht, um den Punkt zu veranschaulichen. Die glibc-Implementierung von
malloc
umfasst 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 haben Sie dadurch einen Überblick darüber bekommen, was das Problem wirklich verursacht!quelle
Meine alternative Lösung zur Verwendung von Valgrind:
Ich bin sehr glücklich, weil ich gerade meinem Freund beim Debuggen eines Programms geholfen habe. Sein Programm hatte genau dieses Problem (
malloc()
was zu einem Abbruch führte) mit der gleichen Fehlermeldung von GDB.Ich habe sein Programm mit Address Sanitizer mit kompiliert
gcc -Wall -g3 -fsanitize=address -o new new.c ^^^^^^^^^^^^^^^^^^
Und dann rannte
gdb new
. Wenn das Programm durchSIGABRT
verursacht in einer Folge beendet wirdmalloc()
, 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 Stapelverfolgung:
Der erste Teil besagt, dass bei eine ungültige Schreiboperation vorliegt
new.c:59
. Diese Zeile lautetmemset(len,0,sizeof(int*)*p); ^^^^^^^^^^^^
Der zweite Teil besagt, dass der Speicher, in dem das fehlerhafte Schreiben stattgefunden hat, bei erstellt wird
new.c:55
. Diese Zeile lautetif(!(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 einige Stunden lang verwirrte. Er hat es geschafft, den Fehler zu lokalisieren, aber es ist ein nachfolgender
malloc()
Aufruf, der fehlgeschlagen ist, ohne diesen Fehler im vorherigen Code erkennen zu können.Fazit: Probieren Sie das
-fsanitize=address
von GCC oder Clang. Dies kann beim Debuggen von Speicherproblemen sehr hilfreich sein.quelle
Sie laufen wahrscheinlich irgendwo über das zugewiesene Mem hinaus. dann nimmt der zugrunde liegende sw es nicht auf, bis Sie malloc aufrufen
Möglicherweise ist ein Wachwert überfüllt, der von Malloc gefangen wird.
edit ... hat dies hinzugefügt, um die Hilfe zur Überprüfung der Grenzen zu überprüfen
http://www.lrde.epita.fr/~akim/ccmp/doc/bounds-checking.html
quelle
Ich habe die folgende Nachricht erhalten, ähnlich Ihrer:
Bei der Verwendung von malloc ist bei einem Methodenaufruf ein Fehler aufgetreten. Das Multiplikationszeichen '*' wurde fälschlicherweise mit einem '+' überschrieben, wenn der Faktor nach dem Operator sizeof () - beim Hinzufügen eines Felds zu einem vorzeichenlosen Zeichenarray aktualisiert wurde.
Hier ist der Code, der für den Fehler in meinem Fall verantwortlich ist:
Bei einer anderen Methode habe ich später wieder malloc verwendet und die oben gezeigte Fehlermeldung ausgegeben. Der Anruf war (einfach genug):
Denken Sie daran, dass die Verwendung des '+' - Zeichens beim ersten Aufruf, was zu einer Fehlkalkulation in Kombination mit einer sofortigen Initialisierung des Arrays nach (Überschreiben des Speichers, der nicht dem Array zugeordnet war) führte, einige Verwirrung in der Speicherzuordnung von malloc verursachte. Daher ging der 2. Anruf schief.
quelle
Wir haben diesen Fehler erhalten, weil wir vergessen haben, mit sizeof (int) zu multiplizieren. Beachten Sie, dass das Argument für malloc (..) eine Anzahl von Bytes ist, nicht die Anzahl von Maschinenwörtern oder was auch immer.
quelle
Ich habe das gleiche Problem, ich habe Malloc immer wieder in einer Schleife verwendet, um neue char * string-Daten hinzuzufügen. Ich hatte das gleiche Problem, aber nach der Freigabe wurden die zugewiesenen Speicherprobleme
void free()
sortiertquelle
Ich habe eine Anwendung von Visual C über Linux auf gcc portiert und hatte das gleiche Problem mit
Ich habe denselben Code in eine Suse-Distribution (auf einem anderen Computer) verschoben und habe kein Problem.
Ich vermute, dass die Probleme nicht in unseren Programmen liegen, sondern in der eigenen Bibliothek.
quelle