core.exception.InvalidMemoryOperationError@(0)
Bayan Rafeh via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sun Jan 25 14:06:26 PST 2015
On Sunday, 25 January 2015 at 19:15:54 UTC, ketmar wrote:
> On Sun, 25 Jan 2015 08:41:24 +0000, Bayan Rafeh wrote:
>
>>> I tried what you said and I think I see the problem. I
>>> managed to
>>> create an example program that duplicates the problem:
>>>
>>>
>>> import std.stdio;
>>>
>>> class A {
>>> string path;
>>>
>>> this(string p) {
>>> path = p;
>>> }
>>> ~this() {
>>> }
>>> void a(){}
>>>
>>> void b(){}
>>> }
>>>
>>> class B {
>>> A a;
>>> this() {
>>> this.a = new A("laladiv");
>>> }
>>> ~this() {
>>> delete a;
>>> }
>>> }
>>>
>>> void main() {
>>> B a = new B(); B b = new B(); delete b;
>>> }
>>
>> The solution was just to remove the "delete a" from the
>> destructor if
>> someone comes across this later. Could someone tell me why
>> though?
>
> there is no guarantees on destruction order. and GC will not
> nullify any
> references to collected data. so, `a` can be already collected
> and
> finalized when `B.~this()` is called. yet reference is still
> there, so
> `delete a;` will try to delete already dead object. this will
> lead to
> crash.
>
> without precise GC collector is not able to automatically
> nullify all
> "dead" references. and even if there will be such possibility,
> it can
> slow down collections alot (GC will nullifying alot of
> references that
> aren't used anyway), so i don't think that it do nullifying.
>
> there is a simple rule: "dtor should not touch GC-managed
> resources".
> this will not give you "predictable destruction order" (that's
> why most
> people try to manually delete something in dtor), and this
> simply will
> not work at all.
>
> if you want predictable destruction order, don't use GC at all,
> use
> manual memory management. it doesn't matter which hack you will
> invent to
> force destruction order, any hack will either be very fragile,
> or will
> not work. this is due to nature of GC-manged memory.
>
> so: don't use GC-managed resources in dtors. don't use in any
> way -- this
> including accessing 'em. i.e. reading `a.path` in dtor is
> invalid too. it
> will not necessarily crash, but it's the source of "use after
> free" error.
>
> and don't even think that you can trick GC using checks from
> `core.memory`! this will not work too. sure, you can check if
> memory used
> by `a` is still alive, but that memory can be used by completely
> different object!
>
> tl;dr:
> 1. don't use GC-managed objects in dtors. not even try to
> access 'em.
> 2. don't try to trick GC. either don't use it, or cooperate
> with it.
All right, I removed all my destructors(turns out I don't really
need them), but I'm still running into this very same error.
This is another problematic example program:
import std.stdio;
void main(){
auto a = new A("/tmp/invalid");
}
class A {
File f;
string path;
this(string path) {
this.path = path;
// f = File(path, "r");
}
invariant() {
File test = File(path, "r");
}
}
is invariant() called during the destruction phase?
More information about the Digitalmars-d-learn
mailing list