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.
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:
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.
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.
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: