Re: InvalidMemoryOperationError when calling functions from destructors
On Sun, 28 Apr 2013 16:25:06 -0700, Vladimir Panteleev wrote: On Sunday, 28 April 2013 at 14:44:32 UTC, Steven Schveighoffer wrote: No, destructors are called along with deallocation. At the moment, the GC mutex is held while the collection is in progress, so it's not possible that a deallocated block could be reallocated before a dtor that references that block is called. Right, so it makes no difference in practice. What I meant was that IIRC early versions of the GC used to rebuild internal free lists, and clobber freed data, in-loop with calling destructors. Thus, when referencing something in a destructor, sometimes you'd get the same object (not yet finalized), and sometimes you'd get garbage. Now you get a finalized object instead of garbage. This was not a "bug," probably (can't be definite on it, since I'm unaware of how the GC used to work). But that is an implementation detail. There is no requirement for the GC to behave that way. I don't disagree with you, but do we have a spec for GCs? AFAIK there is no spec, it's all based on the compiler implementation. For all I know, the GC on GDC or LDC may have a different API. I'd think preserving memory safety, even in a destructor, would be pretty important for a GC design. I wouldn't expect it. code is code, not sure how you can guarantee memory safety in a dtor. In addition, there is no requirement for the GC to run in a specific thread, so if a destroyed object references a non-destroyed object, it's possible some thread is using the non-destroyed object while the dtor is using it in another thread, even if the object was only ever accessed from one thread! Sorry, not following. What's the problem? How is this related? Like an unlocked reference counter, let's say. It's only ever used in one thread. But then an object with a reference becomes garbage. Another thread then runs the garbage collector, enabling race conditions that would not normally be possible. -Steve
Re: InvalidMemoryOperationError when calling functions from destructors
On Sunday, 28 April 2013 at 14:44:32 UTC, Steven Schveighoffer wrote: On Sat, 27 Apr 2013 07:58:25 -0700, Vladimir Panteleev wrote: On Saturday, 27 April 2013 at 06:12:03 UTC, Steven Schveighoffer wrote: On Thu, 25 Apr 2013 10:57:13 -0700, Vladimir Panteleev 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). No, destructors are called along with deallocation. At the moment, the GC mutex is held while the collection is in progress, so it's not possible that a deallocated block could be reallocated before a dtor that references that block is called. Right, so it makes no difference in practice. What I meant was that IIRC early versions of the GC used to rebuild internal free lists, and clobber freed data, in-loop with calling destructors. Thus, when referencing something in a destructor, sometimes you'd get the same object (not yet finalized), and sometimes you'd get garbage. Now you get a finalized object instead of garbage. But that is an implementation detail. There is no requirement for the GC to behave that way. I don't disagree with you, but do we have a spec for GCs? I'd think preserving memory safety, even in a destructor, would be pretty important for a GC design. In addition, there is no requirement for the GC to run in a specific thread, so if a destroyed object references a non-destroyed object, it's possible some thread is using the non-destroyed object while the dtor is using it in another thread, even if the object was only ever accessed from one thread! Sorry, not following. What's the problem? How is this related?
Re: InvalidMemoryOperationError when calling functions from destructors
On Sat, 27 Apr 2013 07:58:25 -0700, Vladimir Panteleev wrote: On Saturday, 27 April 2013 at 06:12:03 UTC, Steven Schveighoffer wrote: On Thu, 25 Apr 2013 10:57:13 -0700, Vladimir Panteleev 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). No, destructors are called along with deallocation. At the moment, the GC mutex is held while the collection is in progress, so it's not possible that a deallocated block could be reallocated before a dtor that references that block is called. But that is an implementation detail. There is no requirement for the GC to behave that way. In addition, there is no requirement for the GC to run in a specific thread, so if a destroyed object references a non-destroyed object, it's possible some thread is using the non-destroyed object while the dtor is using it in another thread, even if the object was only ever accessed from one thread! -Steve
Re: InvalidMemoryOperationError when calling functions from destructors
On Saturday, 27 April 2013 at 06:12:03 UTC, Steven Schveighoffer wrote: On Thu, 25 Apr 2013 10:57:13 -0700, Vladimir Panteleev 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).
Re: InvalidMemoryOperationError when calling functions from destructors
On Thu, 25 Apr 2013 10:57:13 -0700, Vladimir Panteleev 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
Re: InvalidMemoryOperationError when calling functions from destructors
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.)
Re: InvalidMemoryOperationError when calling functions from destructors
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
Re: InvalidMemoryOperationError when calling functions from destructors
> 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.
Re: InvalidMemoryOperationError when calling functions from destructors
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
Re: InvalidMemoryOperationError when calling functions from destructors
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.
Re: InvalidMemoryOperationError when calling functions from destructors
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
Re: InvalidMemoryOperationError when calling functions from destructors
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.
InvalidMemoryOperationError when calling functions from destructors
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.