Was ist der Unterschied zwischen "bracket (mallocBytes n) free" und "allocaBytes"?

8

Wenn Sie Hintergrundinformationen wünschen, finden Sie hier . Kurz gesagt, die Frage ist: "Was ist der tatsächliche Unterschied zwischen bracket (mallocBytes n) free und allocaBytes von Foreign.Marshall.Alloc ".

Normalerweise wird in C alloca auf Stapel und malloc auf Heap allokiert. Ich bin mir nicht sicher, was in Haskell los ist, aber ich würde keinen Unterschied zwischen den oben erwähnten Gleichungen außer der Geschwindigkeit erwarten. Wenn Sie jedoch auf den Hintergrund-Link geklickt haben, wissen Sie, dass der kompilierte Code bracket (mallocBytes n) free zu "double free or corruption" führt, während allocaBytes gut funktioniert (das Problem ist in GHCi gar nicht sichtbar, in beiden Fällen funktioniert alles ).

Inzwischen habe ich zwei Tage mit schmerzhaftem Debugging verbracht und ich bin ziemlich sicher, dass bracket (mallocBytes n) free irgendwie instabil war und der Rest des Codes zuverlässig ist. Ich würde gerne herausfinden, wie es mit bracket (mallocBytes n) free aussieht.

    
Mark 31.12.2016, 18:29
quelle

2 Antworten

12

bracket (mallocBytes size) free verwendet Cs malloc und free , während allocaBytes size Speicher verwendet, der von GHCs Garbage Collection verwaltet wird. Das ist schon ein großer Unterschied, da die Ptr von allocaBytes möglicherweise von ungenutztem (aber zugewiesenem) Speicher umgeben sind:

%Vor%

Ergebnis:

%Vor%

Wie Sie sehen können, hat arr[-1] = 0 , obwohl wir allocaBytes verwendet haben, diesen Fehler gerne ignoriert. Allerdings wird free (oft) in deinem Gesicht explodieren, wenn du in die Position -1 schreibst. Es wird auch in deinem Gesicht explodieren, wenn eine Speicherbeschädigung in einem anderen zugewiesenen Speicherbereich aufgetreten ist *.

Mit allocaBytes ist es auch wahrscheinlich, dass der Zeiger irgendwo in bereits zugewiesenen Speicher zeigt, nicht auf den Anfang von einem, z. B.

%Vor%

Was heißt das? Nun, allocaBytes ist weniger wahrscheinlich in die Luft gesprengt, aber auf Kosten, dass Sie nicht bemerken, wenn Ihre C-Code-Variante zu Speicherbeschädigung führen würde. Schlimmer noch, sobald Sie außerhalb der Grenzen schreiben, die von allocaBytes zurückgegeben werden, können Sie Ihre anderen Haskell Werte möglicherweise verfälschen.

Wir sprechen hier jedoch von undefiniertem Verhalten. Der obige Code kann auf Ihrem System abstürzen oder auch nicht. Es kann auch im allocaBytes -Teil abstürzen.

Wenn ich Sie wäre, würde ich die Aufrufe malloc und free verfolgen .

* Ich hatte einmal mitten in meinem Programm einen "doppelten Gebrauch von freiem" Fehler. Entgegnete alles, schrieb den Großteil der "schlechten" Routine um. Leider ist der Fehler in Debug-Builds verschwunden, aber in Release-Builds erneut aufgetreten. Es stellte sich heraus, dass ich in den ersten zehn Zeilen von main versehentlich in b[i - 1] mit i = 0 geschrieben habe.

    
Zeta 31.12.2016, 20:18
quelle
5

Ich war in der Lage, das Problem zu reproduzieren, und ich kann bestätigen, dass es einen erheblichen Pufferüberlauf gibt. Wenn Sie den folgenden Allokator verwenden (bitte entschuldigen Sie den schnellen und schmutzigen Code), der nach dem Puffer den Wert 0xa5 s einer Seite hinzufügt und ihn bei einer Änderung ausgibt, können Sie in mehreren Tests einen Überlauf von mehreren hundert Bytes sehen:

%Vor%     
K. A. Buhr 31.12.2016 21:01
quelle

Tags und Links