Thread overview | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 04, 2014 [Issue 1164] Wrong order of memory deallocation | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=1164 Pieter Penninckx <pieter.penninckx@scarlet.be> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |pieter.penninckx@scarlet.be Version|D1 |2.040 --- Comment #5 from Pieter Penninckx <pieter.penninckx@scarlet.be> --- Reproduced with DMD version 2.065. If the destructor cannot reference sub objects, this implies that also an invariant cannot reference sub objects, because an invariant is called just before the destructor. Example below triggers segfault with DMD version 2.065. class B { double a, b, c, d, e, f, g, h; bool fun() const { return true; } } class A { B b; invariant() { assert(b !is null); if (b.fun()) // <- Segfault here, but b is not null. { assert(true); } } this() { b = new B(); } ~this() {} } int main() { A a = new A(); return 0; } -- |
June 09, 2015 [Issue 1164] Wrong order of memory deallocation | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=1164 Andrei Alexandrescu <andrei@erdani.com> changed: What |Removed |Added ---------------------------------------------------------------------------- Version|2.040 |D2 -- |
December 22, 2016 [Issue 1164] Wrong order of memory deallocation | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=1164 Andrei Alexandrescu <andrei@erdani.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |andrei@erdani.com --- Comment #6 from Andrei Alexandrescu <andrei@erdani.com> --- Couldn't reproduce on dmd 2.072.1. Any better code sample? -- |
December 25, 2016 [Issue 1164] Wrong order of memory deallocation | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=1164 --- Comment #7 from Pieter Penninckx <pieter.penninckx@scarlet.be> --- The following code still segfaults with DMD 2.072.1-0. class X { double a, b, c, d, e, f, g, h; X sibling; bool fun() const { return true; } invariant() { if(sibling !is null) { if (sibling.fun()) { assert(true); } } } this() {sibling = new X(this); } this(X sibling_) {sibling = sibling_;} ~this() {} } int main() { X x = new X(); return 0; } Garbage collector + destructor (or finalizer) is a difficult combination. See for instance this comment (https://github.com/WebAssembly/design/issues/238#issuecomment-116877193) that strongly opposes introducing a destructor in Javascript because this combination can lead to object resurrection (objects made reachable again in a destructor call). -- |
December 25, 2016 [Issue 1164] Wrong order of memory deallocation | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=1164 --- Comment #8 from Andrei Alexandrescu <andrei@erdani.com> --- Cool, was able to repro. Fortunately we have a couple of cards in our sleeve. What we could do is: * Mark * For each collectable object: * Call dtor * (NEW) Obliterate with .init * Sweep That way objects used during destruction will at least find objects in a deterministic state. -- |
December 26, 2016 [Issue 1164] Wrong order of memory deallocation | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=1164 --- Comment #9 from Pieter Penninckx <pieter.penninckx@scarlet.be> --- Just to be sure I understand you correctly. Am I right that the garbage collector currently works as follows: * Mark (= mark all reachable objects as reachable) * For each collectable (= non-reachable) object: * Call dtor * release memory of the collectable object Am I right that the steps you are thinking about can also be formulated as follows: * Mark (= mark all reachable objects as reachable) * For each collectable (= non-reachable) object: * Call dtor * Obliterate with .init * For each collectable object: * release memory of the collectable object -- |
December 26, 2016 [Issue 1164] Wrong order of memory deallocation | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=1164 --- Comment #10 from Andrei Alexandrescu <andrei@erdani.com> --- (In reply to Pieter Penninckx from comment #9) > Just to be sure I understand you correctly. > > Am I right that the garbage collector currently works as follows: > > * Mark (= mark all reachable objects as reachable) > * For each collectable (= non-reachable) object: > * Call dtor > * release memory of the collectable object I don't know exactly. I am pretty certain, however, that freed objects are currently not overwritten with .init. -- |
December 26, 2016 [Issue 1164] Wrong order of memory deallocation | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=1164 safety0ff.bugz <safety0ff.bugz@gmail.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |safety0ff.bugz@gmail.com --- Comment #11 from safety0ff.bugz <safety0ff.bugz@gmail.com> --- (In reply to Pieter Penninckx from comment #7) > > int main() { > X x = new X(); > return 0; > } Your invariant gets called infinitely: x.sibling.sibling == x sibling's invariant() executes before and after sibling.fun() executes. The invariant has the line: if (sibling.fun()) -- |
December 26, 2016 [Issue 1164] Wrong order of memory deallocation | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=1164 --- Comment #12 from safety0ff.bugz <safety0ff.bugz@gmail.com> --- (In reply to Pieter Penninckx from comment #7) > > invariant() { > if(sibling !is null) { > if (sibling.fun()) > { assert(true); } > } > } > Also: https://dlang.org/spec/contracts.html#Invariants "The code in the invariant may not call any public non-static members of the class or struct, either directly or indirectly. Doing so will result in a stack overflow, as the invariant will wind up being called in an infinitely recursive manner." -- |
December 26, 2016 [Issue 1164] Wrong order of memory deallocation | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=1164 --- Comment #13 from safety0ff.bugz <safety0ff.bugz@gmail.com> --- (In reply to Pieter Penninckx from comment #9) > > Am I right that the garbage collector currently works as follows: It currently works as follows: * Mark * For each unmarked object: * Finalize it if necessary * If it can be released without overwriting it do so * For each unmarked unreleased object: * release memory of the object However, you shouldn't rely on this: http://dlang.org/spec/class.html#destructors If you recompile druntime with the MEMSTOMP option, the GC and it will write arbitrary data to finalized memory. Therefore it follows that referencing GC managed objects from invariants of other GC managed objects is unadvised. I think a case could be made for being able to control insertion of invariant calls in destructors. -- |
Copyright © 1999-2021 by the D Language Foundation