Jump to page: 1 2
Thread overview
InvalidMemoryOperationError when calling functions from destructors
Apr 25, 2013
Volfram
Apr 25, 2013
Vladimir Panteleev
Apr 25, 2013
Volfram
Apr 25, 2013
Jacob Carlborg
Apr 25, 2013
Vladimir Panteleev
Apr 25, 2013
David
Apr 26, 2013
Jacob Carlborg
Apr 26, 2013
Volfram
Apr 27, 2013
Vladimir Panteleev
Apr 28, 2013
Vladimir Panteleev
April 25, 2013
I've run into a problem which I'd like to hope is a bug, but let's see if we can figure out if I'm doing something stupid first, eh?

When a destructor calls a function from another module, I get an InvalidMemoryOperationError.  When a destructor calls a function from another class in the same module, and that function calls the function I was trying to call initially, everything seems to go fine.  When a destructor calls a function in the same class, which calls a function in a different module, I get the InvalidMemoryOperationError again.

This may have to do with garbage collector subtleties I'm not familiar with.

Example:

File alpha.d
module alpha;

import beta;

class AlphaClass
{
    BetaClass bc;
    Alpha2Class a2c;

    void cleanup()
    {
        bc.cleanup();//if this is called from the destructor, expect an error.
    }

    public:
    this()
    {
        bc = new BetaClass();
        a2c = new Alpha2Class(bc);
    }
    ~this
    {
        bc.cleanup();//this will cause an error.
        a2c.cleanup();//this works fine
        cleanup();//this will cause an error.
    }
}

class Alpha2Class
{
    BetaClass bc;

    void cleanup()
    {
        bc.cleanup();
    }

    public:
    this(BetaClass initbc)
    {
        bc = initbc;
    }
}

File beta.d

module beta;

class BetaClass
{
    public:
    this()
    {
        //do something
    }
    void cleanup()
    {
        //clean up after the bosses
    }
}

Further info can be provided if necessary.
April 25, 2013
On Thursday, 25 April 2013 at 15:50:27 UTC, Volfram wrote:
> Further info can be provided if necessary.

Can you provide a full program that exhibits the behavior, or at least a stack trace?

You may need to recompile Phobos and Druntime with the -gs flag to enable correct stacktraces.
April 25, 2013
On 2013-04-25 17:50, Volfram wrote:
> I've run into a problem which I'd like to hope is a bug, but let's see
> if we can figure out if I'm doing something stupid first, eh?
>
> When a destructor calls a function from another module, I get an
> InvalidMemoryOperationError.  When a destructor calls a function from
> another class in the same module, and that function calls the function I
> was trying to call initially, everything seems to go fine.  When a
> destructor calls a function in the same class, which calls a function in
> a different module, I get the InvalidMemoryOperationError again.
>
> This may have to do with garbage collector subtleties I'm not familiar
> with.
>
> Example:
>
> File alpha.d
> module alpha;
>
> import beta;
>
> class AlphaClass
> {
>      BetaClass bc;
>      Alpha2Class a2c;
>
>      void cleanup()
>      {
>          bc.cleanup();//if this is called from the destructor, expect an
> error.
>      }
>
>      public:
>      this()
>      {
>          bc = new BetaClass();
>          a2c = new Alpha2Class(bc);
>      }
>      ~this
>      {
>          bc.cleanup();//this will cause an error.
>          a2c.cleanup();//this works fine
>          cleanup();//this will cause an error.
>      }
> }

You cannot access GC controlled memory in class destructors. There's no guarantee in which order the destructors will be called. You don't know if the memory is still valid in a destructor.

-- 
/Jacob Carlborg
April 25, 2013
On Thursday, 25 April 2013 at 16:00:31 UTC, Vladimir Panteleev wrote:
> On Thursday, 25 April 2013 at 15:50:27 UTC, Volfram wrote:
>> Further info can be provided if necessary.
>
> Can you provide a full program that exhibits the behavior, or at least a stack trace?
>
> You may need to recompile Phobos and Druntime with the -gs flag to enable correct stacktraces.

Well I've got a 6000-line hackeneyed game engine in progress built using the kind of logic that usually only I can follow, but I somehow don't think that's what you're after.

Jacob Carlborg: I thought it might be something like that, which is part of the reason I didn't post this in "bug reports."  I'll figure out something else.  Thanks.
April 25, 2013
On Thursday, 25 April 2013 at 16:17:57 UTC, Jacob Carlborg wrote:
> You cannot access GC controlled memory in class destructors.

Not true.

> There's no guarantee in which order the destructors will be called. You don't know if the memory is still valid in a destructor.

The memory is valid, it's just that referenced objects may already be finalized.

Regardless, the above (accessing objects in destructors) is not related to the InvalidMemoryOperationError. See the documentation for it:
http://dlang.org/phobos/core_exception.html#.InvalidMemoryOperationError
April 25, 2013
> Regardless, the above (accessing objects in destructors) is not related to the InvalidMemoryOperationError. See the documentation for it: http://dlang.org/phobos/core_exception.html#.InvalidMemoryOperationError

I had/have the same problem, it also occurs if you allocate in a destructor during RT shutdown. Well other than that I couldn't reproduce it with allocating in destructors or accessing objects owened by the gc in the destructors.

April 26, 2013
On 2013-04-25 19:57, Vladimir Panteleev wrote:

> Regardless, the above (accessing objects in destructors) is not related
> to the InvalidMemoryOperationError. See the documentation for it:
> http://dlang.org/phobos/core_exception.html#.InvalidMemoryOperationError

Yeah, I though that was weird.

-- 
/Jacob Carlborg
April 26, 2013
Further inspection suggests that the BetaClass object I was accessing was already finalized by the time the AlphaClass object got around to trying to mess with it.  Conclusion is that whether it's the in-destructor access or not, it's simply not safe to try to clean things up this way.  I think I have a safer alternative.

What was interesting is that even after the BetaClass object has been cleaned up, I can access any variables it may have contained.  If, for example, it has an integer value that's publicly visible, I can still read that.(haven't tried writing.)
April 27, 2013
On Thu, 25 Apr 2013 10:57:13 -0700, Vladimir Panteleev <vladimir@thecybershadow.net> wrote:

> On Thursday, 25 April 2013 at 16:17:57 UTC, Jacob Carlborg wrote:
>> You cannot access GC controlled memory in class destructors.
>
> Not true.

Can you be more specific?  Maybe the wording was too strong.  Should say "you shouldn't access GC controlled memory in class destructors."

Or are you thinking of some specific case?  Because the opposite of the above is DEFINITELY not true.  I just want to make that clear.

-Steve
April 27, 2013
On Saturday, 27 April 2013 at 06:12:03 UTC, Steven Schveighoffer wrote:
> On Thu, 25 Apr 2013 10:57:13 -0700, Vladimir Panteleev <vladimir@thecybershadow.net> wrote:
>
>> On Thursday, 25 April 2013 at 16:17:57 UTC, Jacob Carlborg wrote:
>>> You cannot access GC controlled memory in class destructors.
>>
>> Not true.
>
> Can you be more specific?  Maybe the wording was too strong.  Should say "you shouldn't access GC controlled memory in class destructors."
>
> Or are you thinking of some specific case?  Because the opposite of the above is DEFINITELY not true.  I just want to make that clear.

Last time I checked, destructors were called separately from deallocation. Thus, referencing memory will not result in undefined behavior. The order of destruction is non-deterministic, but otherwise, it's the same as accessing a clear()'d object, which is perfectly safe (from a memory safety perspective).
« First   ‹ Prev
1 2