Malloc Segmentierungsfehler

8

Hier ist der Teil des Codes, in dem der Segmentierungsfehler auftritt (der Perror wird nicht aufgerufen):

%Vor%

Um genauer zu sein, sagt gdb, dass das segfault innerhalb eines __int_malloc Aufrufs geschieht, was ein Unterroutinen-Aufruf ist, der von malloc gemacht wird.

Da die malloc-Funktion parallel zu anderen Threads aufgerufen wird, dachte ich zunächst, dass dies das Problem sein könnte. Ich habe Version 2.19 von glibc verwendet.

Die Datenstrukturen:

%Vor%

Jetzt die zukünftige Implementierung:

%Vor%

Der Thread-Pool selbst:

%Vor%

Und schließlich die task.c:

%Vor%

Die Warteschlange ist die lfds-blockierungsfreie Warteschlange.

%Vor%

Das Problem tritt auf, wenn die Anzahl der asynchronen Aufrufe sehr hoch ist.

Valgrind-Ausgabe:

%Vor%     
guilhermemtr 26.02.2014, 19:28
quelle

2 Antworten

9

Ich habe herausgefunden, was das Problem ist: ein Stapelüberlauf.

Lassen Sie mich zuerst erklären, warum der Stapelüberlauf innerhalb von malloc auftritt (was wahrscheinlich der Grund dafür ist, dass Sie dies lesen). Als mein Programm ausgeführt wurde, nahm die Stackgröße jedes Mal zu, wenn es (rekursiv) mit der Ausführung einer anderen Task begann (aufgrund der Art, wie ich es programmiert hatte). Aber für jede solche Zeit musste ich eine neue Aufgabe mit malloc zuweisen. Malloc führt jedoch andere Unterroutinenaufrufe durch, wodurch der Stapel seine Größe sogar noch mehr erhöht als ein einfacher Aufruf zum Ausführen einer anderen Aufgabe. Also, was passiert ist, dass, selbst wenn es kein malloc gäbe, ich einen Stapelüberlauf bekommen würde. Da ich jedoch malloc hatte, war der Stapel, in dem der Stapel übergelaufen war, in malloc, bevor er durch einen weiteren rekursiven Aufruf übergelaufen ist. Die folgende Abbildung zeigt, was passiert ist:

Erster Stapelzustand:

%Vor%

stack während des malloc-Aufrufs:

%Vor%

Dann schrumpfte der Stapel wieder und mein Code gab einen neuen rekursiven Aufruf ein:

%Vor%

Dann wurde malloc innerhalb dieses neuen rekursiven Aufrufs erneut aufgerufen. Dieses Mal ist es jedoch übergelaufen:

%Vor%

[Der Rest der Antwort konzentriert sich mehr darauf, warum ich dieses Problem insbesondere in meinem Code hatte.]

Wenn Fibonacci rekursiv beispielsweise mit einer bestimmten Zahl n berechnet wird, wächst die Stapelgröße linear mit dieser Zahl. In diesem Fall erstelle ich jedoch Aufgaben, verwende eine Warteschlange, um sie zu speichern, und entziehe eine (fib) Aufgabe zur Ausführung. Wenn Sie dies auf Papier zeichnen, werden Sie sehen, dass die Anzahl der Aufgaben exponentiell mit dem n wächst, anstatt linear (auch wenn ich einen Stapel verwendet habe, um die Aufgaben so zu speichern, wie sie erstellt wurden, die Anzahl der zugewiesenen Aufgaben als genau wie die Stackgröße würde nur linear mit n wachsen. Was also passiert ist, dass der Stack exponentiell mit n wächst, was zu einem Stacküberlauf führt ... Nun kommt der Teil, warum dieser Überlauf innerhalb des Calls zu malloc auftritt Ich erklärte oben, dass der Stapelüberlauf innerhalb des malloc-Aufrufs stattfand, da der Stapel dort am größten war.Was passiert war, dass der Stapel fast explodierte und da malloc Funktionen darin aufruft, wächst der Stapel mehr als nur der Aufruf von mywait und fib.

Danke euch allen! Wenn es nicht deine Hilfe wäre, wäre ich nicht in der Lage, es herauszufinden!

    
guilhermemtr 27.02.2014, 11:43
quelle
9

Ein SIGSEGV (segmentation fault), der in malloc ausgelöst wird, wird normalerweise durch Heap-Korruption verursacht. Heap Corruption verursacht keinen Segmentierungsfehler, also würden Sie das nur sehen, wenn malloc versucht, darauf zuzugreifen. Das Problem besteht darin, dass der Code, der die Heap-Beschädigung verursacht, an einem beliebigen Punkt weit entfernt von dem Ort sein kann, an dem der malloc aufgerufen wird. Normalerweise wird der Zeiger des nächsten Blocks innerhalb des Mallocs durch Ihre Heap-Beschädigung in eine ungültige Adresse geändert, so dass beim Aufruf von malloc ein ungültiger Zeiger dereferenziert wird und Sie einen Segmentierungsfehler erhalten.

Ich denke, Sie können versuchen, Teile Ihres Codes vom Rest des Programms zu isolieren, um die Sichtbarkeit des Fehlers zu reduzieren.

Außerdem sehe ich, dass Sie hier niemals die Speicher freigeben und es kann zu einem möglichen Speicherleck kommen.

Um einen Speicherleck zu überprüfen, können Sie den obersten Befehl top -b -n 1 ausführen und prüfen:

%Vor%     
Jekyll 26.02.2014 20:48
quelle