blipman17
blipman17

Reputation: 531

access violation in destroy()

I am trying to manage the lifetime from an expensive object using manual memory management and during my unit-tests I seem to crash my program with an access violation in the main method underneath destroy(bar) in this example. This is the minimal example for my problem where I get an access violation.

I don't understand what's going wrong.

class Foo { int i;}

struct Bar
{
    Foo _p;
    this(Foo foo)
    {
        _p = foo;
    }

    ~this() {
        import core.stdc.stdlib : free;
        if (_p !is null)
        {
            destroy(_p);
            free(cast(void*)_p);
            _p = null;
        }
    }
}


void main(string[] argv)
{
    import std.conv;
    import core.stdc.stdlib;

    Foo foo = emplace(cast(Foo) malloc(Foo.sizeof));

    Bar bar = Bar(foo);
    destroy(bar);
}

Upvotes: 3

Views: 177

Answers (1)

Adam D. Ruppe
Adam D. Ruppe

Reputation: 25595

Note that destroy sets _p to null "for" you... which means you never actually free it. Do Foo tmp = _p; destroy(_p); free(cast(void*) tmp); instead, or something like that, so you keep a temporary copy of the reference beyond the destroy call. That's not what's causing your crash though, that is just a memory leak.

The crash is because, Foo.sizeof for a class is the size of the reference, not the size of the instance. For classes, you want to malloc(__traits(classInstanceSize, Foo)). The documentation mentions this as one of its preconditions: http://dpldocs.info/experimental-docs/std.conv.emplace.3.html

That's causing your crash because you didn't allocate enough space for the vtable (and thus emplace probably corrupted memory too, which eluded type checks due to your cast!). I would malloc and slice it instead of casting it.

// malloc the instance size then slice it to get a type-safe representation
void[] memory = malloc(__traits(classInstanceSize, Foo))[0 .. __traits(classInstanceSize, Foo)];
emplace!Foo(memory); // emplace a new one in that memory

You also should be careful when passing class references to that struct, since if it wasn't malloced or if there is another reference, you will get a dangling problem.

Upvotes: 5

Related Questions