question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Finalizer can crash process when native libgit2 failed to load

See original GitHub issue

I’ve hit this myself and worked around it by helping libgit2sharp find the native binary. But for those times when it still fails it should be permissible for the caller to catch the exception regarding not finding the native binary and move on. But in this case, libgit2sharp has a finalizer which ends up re-throwing the exception. And when finalizers throw, the process goes down:

[ERROR] FATAL UNHANDLED EXCEPTION: System.TypeInitializationException: The type initializer for 'LibGit2Sharp.Core.NativeMethods' threw an exception. ---> System.DllNotFoundException: git2-1196807
  at (wrapper managed-to-native) LibGit2Sharp.Core.NativeMethods:git_libgit2_init ()
  at LibGit2Sharp.Core.NativeMethods+LibraryLifetimeObject..ctor () [0x00006] in <48079e5da5364f5db01fd1de5fb12b0d>:0 
  at LibGit2Sharp.Core.NativeMethods..cctor () [0x00054] in <48079e5da5364f5db01fd1de5fb12b0d>:0 
   --- End of inner exception stack trace ---
  at LibGit2Sharp.Core.NativeMethods+LibraryLifetimeObject.Finalize () [0x00000] in <48079e5da5364f5db01fd1de5fb12b0d

By the way, this is too much work for a finalizer to do. The only safe thing for a finalizer (at least during appdomain shutdown) is access structs. Reference types like LibraryLifetimeObject aren’t safe to assume they can be used.

So at least the Finalize method should catch this exception and swallow it. But preferably, it should invoke native methods and access its own struct fields only.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:18 (12 by maintainers)

github_iconTop GitHub Comments

1reaction
ethomsoncommented, Apr 18, 2017

That usual pattern is how to make IDisposable interact nicely with finalizers, so that you don’t wind up invoking the native cleanup in both. We don’t have anything IDisposable here, we only do finalizers, so having Dispose methods wouldn’t have utility for us, and we should just do our native cleanup code.

However I do want to point out that I think that the title of this issue is misleading - despite being in the stack trace, it’s not the finalizer that’s throwing here, it’s the static constructor. Which will fail with a TypeInitializationException since there was an exception in the static constructor. That the finalizer is in the stack trace is a bit odd, I concede. I suppose what’s actually going on is that the finalizer just rethrows the initializer’s exception?

You can make the finalizer trivial (int i = 1+1;) to convince yourself that it’s not doing anything unsafe and it will still be blamed in the stack trace.

Now having said that, we don’t need this reference counting magic anymore. I’m not entirely clear why this would have been useful in the first place. It was so that the SafeHandleBase could ensure that it ran finalizers before calling git_libgit2_shutdown… but I don’t understand how the LibraryLifetimeObject’s finalizer could be called before NativeMethods is “finalized”, which is not deterministic but definitely cannot happen before it’s used last. IOW, nothing that calls NativeMethods can outlast this finalizer… So we don’t need to refcount. (And in fact we don’t; we don’t have objects that extend SafeHandle and do this reference counting anymore, so it’s only ever incremented in the cctor and decremented in the finalizer.)

I’ll simplify the static constructor and the finalizer and just make then call git_libgit2_init and git_libgit2_shtudown, which is all they’re doing anyway.

0reactions
ethomsoncommented, Jun 24, 2017

Fixed via #1438

Read more comments on GitHub >

github_iconTop Results From Across the Web

mono msbuild on Mac/Linux can't find and load libgit2 native binary
mono msbuild on Mac/Linux can't find and load libgit2 native binary #118 ... Finalizer can crash process when native libgit2 failed to load...
Read more >
Crashing on Finalizer SWGEMU
Now I have been unable to join back and play. It starts off by allowing me to launch the game from the SWGemu...
Read more >
Multi-processing and Distributed Computing
Process 1 knew about the function rand2 , but process 2 did not. Most commonly you'll be loading code from files or packages,...
Read more >
Apache Arrow 6.0.1 (2021-11-10)
ARROW-14129 - [C++] An empty dictionary array crashes on `unique` and `value_counts`. ARROW-14139 - [IR] [C++] Table flatbuffer object fails to compile on...
Read more >
Calling C and Fortran Code - Julia Documentation
This form can be used to call C library functions, functions in the Julia runtime, or functions in an application linked to Julia....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found