libgit2/libgit2sharp — pull request #249 by markus-olsson (2012-11-19 00:49:05+00:00)
Title: Make git_threads_shutdown run after git finalizers

## Problem

If you initiate 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 `Repository` destructor attempts to call `git_repository_free` after `git_threads_shutdown` has been called which I'm guessing means that thread local 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 doesn't and I'm guessing that's actually the expected behavior).

## Reproduce it

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` when the GC calls the `Repository` destructor. The obvious and correct way to fix this is to simply make sure that the repo instance gets disposed first:

```c#
static void Main(string[] args) {
using(var repo = new Repository(@"e:\code\misc\libgit2sharp\"))
var changes = repo.Diff.Compare();
}
```

## Possible solution

One way to tackle this problem would be to ignore it and just clearly state the importance of properly disposing 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