Thread overview
How to debug FinalizeError?
Nov 28, 2018
unDEFER
Nov 28, 2018
Adam D. Ruppe
Nov 29, 2018
unDEFER
Nov 29, 2018
unDEFER
November 28, 2018
Hello! After long-long time of debugging, I just have decided InvalidMemoryOperationError in my program. But now my program after few hours of testing again crashes with "Finalization error".

What this error means exactly? I again did something wrong in destructor?
And how to debug it? I tried "break onFinalizeError" in gdb like "break onInvalidMemoryOperationError", but it says:

Function "onFinalizeError" not defined.

There are too few information about this error in documentation and forum, and I didn't find anything about it in wiki.

Thank you.
November 28, 2018
On Wednesday, 28 November 2018 at 22:40:17 UTC, unDEFER wrote:
> Hello! After long-long time of debugging, I just have decided InvalidMemoryOperationError in my program. But now my program after few hours of testing again crashes with "Finalization error".

So InvalidMemoryOperationError means a GC function got called while the GC was locked. This is usually because you did an allocation inside a destructor.

Finalization error happens when a destructor throws an exception.

Now, many times, trying to throw an exception from inside a destructor will first trigger the invalid operation - allocating the exception will be an error before the exception actually exists. But there are a few ways around this, like preallocating or calling a function that uses a statically allocated exception.


Language features that use statically allocated exceptions include:

* InvalidMemoryOperationError
* OutOfMemoryError
* SwitchError

There might be more, but this is all I see right now (my process btw: search the druntime source code for "staticError", the function that makes those. But this is subject to change, so first maybe look up the definition of onOutOfMemoryError and see the pattern there.)


Of these... well, they are all kinda difficult to cause in a destructor.

Are you preallocating something in your code and throwing it in a destructor?



Also, what *exactly* is the message you get when the exception happens? It should include a line number from druntime as well as message from the inner exception that caused it in the first place.
November 29, 2018
No I'm not preallocating any exceptions. It was idea, but I removed all calls which can make throw.
I'm using very old dmd 2.074.1, so as I have patched it for my text editor with IDE functions. I had a year break in development, so now I need to rewrite all my patches.
But exactly the output of my program looks like this:

core.exception.FinalizeError@src/rt/lifetime.d(1407): Finalization error
----------------
=== Bypassed ===

|||||||||||| BerkeleyDB exceptions mixed with output of destructors ||||||||||||||||||

core.exception.InvalidMemoryOperationError@src/core/exception.d(696): Invalid memory operation
----------------

It means that "Invalid memory operation" occurred earlier than "Finalization error"?
The line on which shows the pointer src/rt/lifetime.d(1407) is exactly:
        onFinalizeError(*pc, e);
Why gdb doesn't see this function?

My program (the text editor) had run test all night under gdb with break on InvalidMemoryOperationError and didn't fall. So it is very-very-very hard to reproduce.
And I haven't ideas where maybe this throw. At least I don't see any throw in explicit form.
November 29, 2018
On 11/29/18 2:07 AM, unDEFER wrote:
> No I'm not preallocating any exceptions. It was idea, but I removed all calls which can make throw.
> I'm using very old dmd 2.074.1, so as I have patched it for my text editor with IDE functions. I had a year break in development, so now I need to rewrite all my patches.
> But exactly the output of my program looks like this:
> 
> core.exception.FinalizeError@src/rt/lifetime.d(1407): Finalization error
> ----------------
> === Bypassed ===
> 
> |||||||||||| BerkeleyDB exceptions mixed with output of destructors ||||||||||||||||||
> 
> core.exception.InvalidMemoryOperationError@src/core/exception.d(696): Invalid memory operation
> ----------------
> 
> It means that "Invalid memory operation" occurred earlier than "Finalization error"?
> The line on which shows the pointer src/rt/lifetime.d(1407) is exactly:
>          onFinalizeError(*pc, e);
> Why gdb doesn't see this function?

You need to compile druntime in debug mode. One thing you can do is implement the function locally, and then break on it (it's a C linkage, so I think the linker will grab your copy instead of the one in druntime)

i.e. in your code, do:

extern(C) void onFinalizeError(TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__)
{
   import core.stdc.stdio;
   printf("break here\n");
}

> 
> My program (the text editor) had run test all night under gdb with break on InvalidMemoryOperationError and didn't fall. So it is very-very-very hard to reproduce.
> And I haven't ideas where maybe this throw. At least I don't see any throw in explicit form.

These are unfortunately really tough to debug. You get very little info, and the stack trace is generally useless.

-Steve
November 29, 2018
On Thursday, 29 November 2018 at 14:51:40 UTC, Steven Schveighoffer wrote:
> You need to compile druntime in debug mode. One thing you can do is implement the function locally, and then break on it (it's a C linkage, so I think the linker will grab your copy instead of the one in druntime)
>
> i.e. in your code, do:
>
> extern(C) void onFinalizeError(TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__)
> {
>    import core.stdc.stdio;
>    printf("break here\n");
> }

Big thanks, Steve. I will try it. Every night will do debugging and maybe at one night it will happen again :-)