11using System ;
2- using System . Globalization ;
32using System . IO ;
43using System . Runtime . CompilerServices ;
4+ using System . Runtime . ConstrainedExecution ;
55using System . Runtime . InteropServices ;
66using LibGit2Sharp . Core . Handles ;
77
8+ // Restrict the set of directories where the native library is loaded from to safe directories.
9+ [ assembly: DefaultDllImportSearchPaths ( DllImportSearchPath . AssemblyDirectory | DllImportSearchPath . ApplicationDirectory | DllImportSearchPath . SafeDirectories ) ]
10+
11+ #pragma warning disable IDE1006 // Naming Styles
12+
813// ReSharper disable InconsistentNaming
914namespace LibGit2Sharp . Core
1015{
@@ -17,41 +22,68 @@ internal static class NativeMethods
1722 // This will handle initialization and shutdown of the underlying
1823 // native library.
1924#pragma warning disable 0414
20- private static readonly NativeShutdownObject shutdownObject ;
21- #pragma warning restore 0414
25+ private static NativeShutdownObject shutdownObject ;
26+ #pragma warning restore 0414
2227
2328 static NativeMethods ( )
2429 {
25- if ( Platform . OperatingSystem == OperatingSystemType . Windows )
30+ if ( Platform . IsRunningOnNetFramework ( ) || Platform . IsRunningOnNetCore ( ) )
2631 {
27- string nativeLibraryPath = GlobalSettings . GetAndLockNativeLibraryPath ( ) ;
28-
29- string path = Path . Combine ( nativeLibraryPath , Platform . ProcessorArchitecture ) ;
30-
31- const string pathEnvVariable = "PATH" ;
32- Environment . SetEnvironmentVariable ( pathEnvVariable ,
33- String . Format ( CultureInfo . InvariantCulture , "{0}{1}{2}" , path , Path . PathSeparator , Environment . GetEnvironmentVariable ( pathEnvVariable ) ) ) ;
32+ string nativeLibraryDir = GlobalSettings . GetAndLockNativeLibraryPath ( ) ;
33+ if ( nativeLibraryDir != null )
34+ {
35+ string nativeLibraryPath = Path . Combine ( nativeLibraryDir , libgit2 + Platform . GetNativeLibraryExtension ( ) ) ;
36+
37+ // Try to load the .dll from the path explicitly.
38+ // If this call succeeds further DllImports will find the library loaded and not attempt to load it again.
39+ // If it fails the next DllImport will load the library from safe directories.
40+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
41+ {
42+ LoadWindowsLibrary ( nativeLibraryPath ) ;
43+ }
44+ else
45+ {
46+ LoadUnixLibrary ( nativeLibraryPath , RTLD_NOW ) ;
47+ }
48+ }
3449 }
3550
36- LoadNativeLibrary ( ) ;
37- shutdownObject = new NativeShutdownObject ( ) ;
51+ InitializeNativeLibrary ( ) ;
3852 }
3953
54+ public const int RTLD_NOW = 0x002 ;
55+
56+ [ DllImport ( "libdl" , EntryPoint = "dlopen" ) ]
57+ private static extern IntPtr LoadUnixLibrary ( string path , int flags ) ;
58+
59+ [ DllImport ( "kernel32" , EntryPoint = "LoadLibrary" ) ]
60+ private static extern IntPtr LoadWindowsLibrary ( string path ) ;
61+
4062 // Avoid inlining this method because otherwise mono's JITter may try
4163 // to load the library _before_ we've configured the path.
4264 [ MethodImpl ( MethodImplOptions . NoInlining ) ]
43- private static void LoadNativeLibrary ( )
65+ private static void InitializeNativeLibrary ( )
4466 {
45- // Configure the OpenSSL locking on the true initialization
46- // of the library.
47- if ( git_libgit2_init ( ) == 1 )
67+ int initCounter ;
68+ try
69+ {
70+ }
71+ finally // avoid thread aborts
72+ {
73+ // Initialization can be called multiple times as long as there is a corresponding shutdown to each initialization.
74+ initCounter = git_libgit2_init ( ) ;
75+ shutdownObject = new NativeShutdownObject ( ) ;
76+ }
77+
78+ // Configure the OpenSSL locking on the first initialization of the library in the current process.
79+ if ( initCounter == 1 )
4880 {
4981 git_openssl_set_locking ( ) ;
5082 }
5183 }
5284
5385 // Shutdown the native library in a finalizer.
54- private sealed class NativeShutdownObject
86+ private sealed class NativeShutdownObject : CriticalFinalizerObject
5587 {
5688 ~ NativeShutdownObject ( )
5789 {
0 commit comments