diff --git a/CHANGES.md b/CHANGES.md index 790f7a84f..4dfb74cbf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,9 @@ ### Fixes + - The exception thrown when the native library cannot be loaded is now + able to be caught and will no longer crash the process. + ## v0.24 - ([diff](https://github.com/libgit2/libgit2sharp/compare/v0.23..v0.24)) This is the last release before a moving to .NET Core compatible library. diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index f2ea4f68a..3156942f3 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -17,62 +17,13 @@ internal static partial class NativeMethods { public const uint GIT_PATH_MAX = 4096; private const string libgit2 = NativeDllName.Name; - // This is here to keep the pointer alive -#pragma warning disable 0414 - private static readonly LibraryLifetimeObject lifetimeObject; -#pragma warning restore 0414 - private static int handlesCount; - - /// - /// Internal hack to ensure that the call to git_threads_shutdown is called after all handle finalizers - /// have run to completion ensuring that no dangling git-related finalizer runs after git_threads_shutdown. - /// There should never be more than one instance of this object per AppDomain. - /// - private sealed class LibraryLifetimeObject -#if DESKTOP - : CriticalFinalizerObject -#endif - { - // Ensure mono can JIT the .cctor and adjust the PATH before trying to load the native library. - // See https://github.com/libgit2/libgit2sharp/pull/190 - [MethodImpl(MethodImplOptions.NoInlining)] - public LibraryLifetimeObject() - { - int res = git_libgit2_init(); - Ensure.Int32Result(res); - if (res == 1) - { - // Ignore the error that this propagates. Call it in case openssl is being used. - git_openssl_set_locking(); - } - AddHandle(); - } - - ~LibraryLifetimeObject() - { - RemoveHandle(); - } - } - -#if DESKTOP - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] -#endif - internal static void AddHandle() - { - Interlocked.Increment(ref handlesCount); - } -#if DESKTOP - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] -#endif - internal static void RemoveHandle() - { - int count = Interlocked.Decrement(ref handlesCount); - if (count == 0) - { - git_libgit2_shutdown(); - } - } + // An object tied to the lifecycle of the NativeMethods static class. + // This will handle initialization and shutdown of the underlying + // native library. + #pragma warning disable 0414 + private static readonly NativeShutdownObject shutdownObject; + #pragma warning restore 0414 static NativeMethods() { @@ -87,8 +38,30 @@ static NativeMethods() String.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", path, Path.PathSeparator, Environment.GetEnvironmentVariable(pathEnvVariable))); } - // See LibraryLifetimeObject description. - lifetimeObject = new LibraryLifetimeObject(); + LoadNativeLibrary(); + shutdownObject = new NativeShutdownObject(); + } + + // Avoid inlining this method because otherwise mono's JITter may try + // to load the library _before_ we've configured the path. + [MethodImpl(MethodImplOptions.NoInlining)] + private static void LoadNativeLibrary() + { + // Configure the OpenSSL locking on the true initialization + // of the library. + if (git_libgit2_init() == 1) + { + git_openssl_set_locking(); + } + } + + // Shutdown the native library in a finalizer. + private sealed class NativeShutdownObject + { + ~NativeShutdownObject() + { + git_libgit2_shutdown(); + } } [DllImport(libgit2)]