You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make git_threads_shutdown run after git finalizers
When initiating a repository in order to extract a diff between the last
commit and the working directory and 'forget'/ignore to properly dispose
of the Repository instance you'll get an AccessViolationException on
application shutdown.
The problem is that the finalizer for Repository attempts to call
git_repository_free after git_threads_shutdown has been called meaning
that TLS-state which is potentially required as part of a shutdown isn't
available.
git_threads_shutdown is supposed to be called right before "shutting
down" the library. See [global.c L16-40][1]. At the moment the call to
git_threads_shutdown is done from the [AppDomain.ProcessExit][2] event.
The problem is that the MSDN doesn't guarantee that
[AppDomain.ProcessExit][2] runs after finalizers (on my machine it never
does and I'm guessing that's actually the expected behavior).
Here's an example of how to reproduce it:
```c#
static void Main(string[] args) {
// path to repo which contains changes in the working directory.
var repo = new Repository(@"e:\code\misc\libgit2sharp\");
var changes = repo.Diff.Compare();
}
```
This will throw an AccessViolationException in git_repository_free. The
obvious and correct way to fix this is to simply make sure that the repo
instance gets disposed.
```c#
static void Main(string[] args) {
// path to repo which contains changes in the working directory.
using(var repo = new Repository(@"e:\code\misc\libgit2sharp\"))
var changes = repo.Diff.Compare();
}
```
One way to tackle this problem would be to clearly state that you really
have to dispose your repositories but since libgit2sharp seems to be doing
a lot of work to shut down cleanly in finalizers today I thought we should
at least discuss it.
My hackish workaround is to create an object which derives from
[CriticalFinalizerObject][3] which calls git_threads_init in the
constructor and git_threads_shutdown in the destructor. Since this object
is a CriticalFinalizerObject its destructor will run after any 'regular'
destructors such as the Repository destructor thus ensuring that
git_threads_shutdown is the last thing to happen on the PInvoke-side
before the AppDomain is completely done.
From the blog of [Chris Brumme][4]:
> All normal finalizable objects are either executed or discarded without
> finalization, before any critical finalizers are executed.
[1]: https://github.com/libgit2/libgit2/blob/development/src/global.c#L16-L40
[2]: http://msdn.microsoft.com/en-us/library/system.appdomain.processexit.aspx
[3]: http://msdn.microsoft.com/en-us/library/system.runtime.constrainedexecution.criticalfinalizerobject.aspx
[4]: http://blogs.msdn.com/b/cbrumme/archive/2004/02/20/77460.aspx
0 commit comments