diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs
index 7392b4de5daa6d..67f0e8205d0a33 100644
--- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs
+++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs
@@ -141,7 +141,9 @@ static MsQuicApi()
return;
}
- if (!NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out IntPtr msQuicHandle))
+ // Windows ships msquic in the assembly directory. Non-Windows relies an the package being installed on the system.
+ DllImportSearchPath? searchPath = OperatingSystem.IsWindows() ? DllImportSearchPath.AssemblyDirectory : null;
+ if (!NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, searchPath, out IntPtr msQuicHandle))
{
// MsQuic library not loaded
return;
diff --git a/src/mono/mono/metadata/native-library.c b/src/mono/mono/metadata/native-library.c
index f01b9efbae5ddb..083e7cad5e9d76 100644
--- a/src/mono/mono/metadata/native-library.c
+++ b/src/mono/mono/metadata/native-library.c
@@ -92,7 +92,7 @@ mono_dllmap_lookup_list (MonoDllMap *dll_map, const char *dll, const char* func,
if (!dll_map)
goto exit;
- /*
+ /*
* we use the first entry we find that matches, since entries from
* the config file are prepended to the list and we document that the
* later entries win.
@@ -254,7 +254,7 @@ mono_global_dllmap_cleanup (void)
* This function is used to programatically add \c DllImport remapping in either
* a specific assembly, or as a global remapping. This is done by remapping
* references in a \c DllImport attribute from the \p dll library name into the \p tdll
- * name. If the \p dll name contains the prefix i:, the comparison of the
+ * name. If the \p dll name contains the prefix i:, the comparison of the
* library name is done without case sensitivity.
*
* If you pass \p func, this is the name of the \c EntryPoint in a \c DllImport if specified
@@ -518,8 +518,11 @@ netcore_probe_for_module (MonoImage *image, const char *file_name, int flags)
// TODO: this algorithm doesn't quite match CoreCLR, so respecting DLLIMPORTSEARCHPATH_LEGACY_BEHAVIOR makes little sense
// If the difference becomes a problem, overhaul this algorithm to match theirs exactly
- // Try without any path additions
+#if defined(HOST_ANDROID)
+ // On Android, try without any path additions first. It is sensitive to probing that will always miss
+ // and lookup for some libraries is required to use a relative path
module = netcore_probe_for_module_variations (NULL, file_name, lflags);
+#endif
// Check the NATIVE_DLL_SEARCH_DIRECTORIES
for (int i = 0; i < pinvoke_search_directories_count && module == NULL; ++i)
@@ -533,6 +536,14 @@ netcore_probe_for_module (MonoImage *image, const char *file_name, int flags)
g_free (mdirname);
}
+#if !defined(HOST_ANDROID)
+ // Try without any path additions
+ if (module == NULL)
+ {
+ module = netcore_probe_for_module_variations (NULL, file_name, lflags);
+ }
+#endif
+
// TODO: Pass remaining flags on to LoadLibraryEx on Windows where appropriate, see https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportsearchpath?view=netcore-3.1
return module;
@@ -1048,7 +1059,7 @@ lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_ou
mono_custom_attrs_free (cinfo);
}
if (flags < 0)
- flags = 0;
+ flags = DLLIMPORTSEARCHPATH_ASSEMBLY_DIRECTORY;
module = netcore_lookup_native_library (alc, image, new_scope, flags);
if (!module) {
@@ -1154,7 +1165,7 @@ pinvoke_probe_for_symbol (MonoDl *module, MonoMethodPInvoke *piinfo, const char
#if HOST_WIN32 && HOST_X86
/* Try the stdcall mangled name */
- /*
+ /*
* gcc under windows creates mangled names without the underscore, but MS.NET
* doesn't support it, so we doesn't support it either.
*/
@@ -1394,7 +1405,7 @@ mono_loader_save_bundled_library (int fd, uint64_t offset, uint64_t size, const
char *file, *buffer, *err, *internal_path;
if (!bundle_save_library_initialized)
bundle_save_library_initialize ();
-
+
file = g_build_filename (bundled_dylibrary_directory, destfname, (const char*)NULL);
buffer = g_str_from_file_region (fd, offset, size);
g_file_set_contents (file, buffer, size, NULL);
@@ -1409,7 +1420,7 @@ mono_loader_save_bundled_library (int fd, uint64_t offset, uint64_t size, const
mono_loader_register_module (internal_path, lib);
g_free (internal_path);
bundle_library_paths = g_slist_append (bundle_library_paths, file);
-
+
g_free (buffer);
}
diff --git a/src/tests/Common/CoreCLRTestLibrary/Utilities.cs b/src/tests/Common/CoreCLRTestLibrary/Utilities.cs
index bd1eb1be37de73..4e22339154be8c 100644
--- a/src/tests/Common/CoreCLRTestLibrary/Utilities.cs
+++ b/src/tests/Common/CoreCLRTestLibrary/Utilities.cs
@@ -68,6 +68,9 @@ public static bool Verbose
public static bool IsWindows7 => IsWindows && Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1;
public static bool IsWindowsNanoServer => (!IsWindowsIoTCore && GetInstallationType().Equals("Nano Server", StringComparison.OrdinalIgnoreCase));
+ private static string _variant = Environment.GetEnvironmentVariable("DOTNET_RUNTIME_VARIANT");
+ public static bool IsMonoLLVMFULLAOT => _variant == "llvmfullaot";
+
// Windows 10 October 2018 Update
public static bool IsWindows10Version1809OrGreater =>
IsWindows && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildNumber() >= 17763;
diff --git a/src/tests/Common/testenvironment.proj b/src/tests/Common/testenvironment.proj
index c6d0a7c358d155..293feb331da49c 100644
--- a/src/tests/Common/testenvironment.proj
+++ b/src/tests/Common/testenvironment.proj
@@ -201,6 +201,8 @@
<_TestEnvFileLine Condition="'$(RuntimeVariant)' == 'monointerpreter'" Include="set MONO_ENV_OPTIONS=--interpreter" />
+ <_TestEnvFileLine Condition="'$(RuntimeVariant)' != ''" Include="set DOTNET_RUNTIME_VARIANT=$(RuntimeVariant)" />
+
<_TestEnvFileLine Condition="'$(Scenario)' == 'clrinterpreter'" Include="set COMPlus_Interpret=%2A" />
<_TestEnvFileLine Condition="'$(Scenario)' == 'clrinterpreter'" Include="set COMPlus_InterpreterHWIntrinsicsIsSupportedFalse=1" />
@@ -216,6 +218,8 @@
<_TestEnvFileLine Condition="'$(RuntimeVariant)' == 'monointerpreter'" Include="export MONO_ENV_OPTIONS=--interpreter" />
+ <_TestEnvFileLine Condition="'$(RuntimeVariant)' != ''" Include="export DOTNET_RUNTIME_VARIANT=$(RuntimeVariant)" />
+
<_TestEnvFileLine Condition="'$(RuntimeVariant)' == 'llvmaot'" Include="export MONO_ENV_OPTIONS=--llvm" />
diff --git a/src/tests/Interop/DllImportSearchPaths/DllImportSearchPathsTest.cs b/src/tests/Interop/DllImportSearchPaths/DllImportSearchPathsTest.cs
new file mode 100644
index 00000000000000..dcc6514ece1f15
--- /dev/null
+++ b/src/tests/Interop/DllImportSearchPaths/DllImportSearchPathsTest.cs
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Xunit;
+
+public class DllImportSearchPathsTest
+{
+ private static string Subdirectory => Path.Combine(NativeLibraryToLoad.GetDirectory(), "subdirectory");
+
+ static int Main(string[] args)
+ {
+ try
+ {
+ AssemblyDirectory_NotFound();
+ if (!TestLibrary.Utilities.IsMonoLLVMFULLAOT)
+ AssemblyDirectory_Found();
+
+ if (OperatingSystem.IsWindows())
+ AssemblyDirectory_Fallback_Found();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Test Failure: {e}");
+ return 101;
+ }
+
+ return 100;
+ }
+
+ public static void AssemblyDirectory_NotFound()
+ {
+ // Library should not be found in the assembly directory
+ Assert.Throws(() => NativeLibraryPInvoke.Sum(1, 2));
+ }
+
+ public static void AssemblyDirectory_Found()
+ {
+ // Library should be found in the assembly directory
+ var assembly = Assembly.LoadFile(Path.Combine(Subdirectory, $"{nameof(DllImportSearchPathsTest)}.dll"));
+ var type = assembly.GetType(nameof(NativeLibraryPInvoke));
+ var method = type.GetMethod(nameof(NativeLibraryPInvoke.Sum));
+
+ int sum = (int)method.Invoke(null, new object[] { 1, 2 });
+ Assert.Equal(3, sum);
+ }
+
+ public static void AssemblyDirectory_Fallback_Found()
+ {
+ string currentDirectory = Environment.CurrentDirectory;
+ try
+ {
+ Environment.CurrentDirectory = Subdirectory;
+
+ // Library should not be found in the assembly directory, but should fall back to the default OS search which includes CWD on Windows
+ int sum = NativeLibraryPInvoke.Sum(1, 2);
+ Assert.Equal(3, sum);
+ }
+ finally
+ {
+ Environment.CurrentDirectory = currentDirectory;
+ }
+ }
+}
+
+public class NativeLibraryPInvoke
+{
+ public static int Sum(int a, int b)
+ {
+ return NativeSum(a, b);
+ }
+
+ [DllImport(NativeLibraryToLoad.Name)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)]
+ static extern int NativeSum(int arg1, int arg2);
+}
diff --git a/src/tests/Interop/DllImportSearchPaths/DllImportSearchPathsTest.csproj b/src/tests/Interop/DllImportSearchPaths/DllImportSearchPathsTest.csproj
new file mode 100644
index 00000000000000..70277c524034f7
--- /dev/null
+++ b/src/tests/Interop/DllImportSearchPaths/DllImportSearchPathsTest.csproj
@@ -0,0 +1,25 @@
+
+
+ Exe
+ true
+
+
+
+
+
+
+
+
+
+ $(OutDir)/subdirectory
+ -in-subdirectory
+
+
+ <_FilesToCopy Include="$(OutDir)/$(TargetName).dll" />
+ <_FilesToMove Include="$(OutDir)/libNativeLibrary.*" />
+ <_FilesToMove Include="$(OutDir)/NativeLibrary.*" />
+
+
+
+
+
diff --git a/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.cs b/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.cs
index 4742b2e0b5bdbb..699a125dfb2c42 100644
--- a/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.cs
+++ b/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.cs
@@ -110,13 +110,22 @@ public static int Main()
if (TestLibrary.Utilities.IsWindows &&
File.Exists(Path.Combine(Environment.SystemDirectory, libName)))
{
- // Calls on a valid library from System32 directory
+ // Library should be found in the system directory
success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.System32));
success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.System32));
- // Calls on a valid library from application directory
+ // Library should not be found in the assembly directory and should be found in the system directory
+ success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.System32));
+ success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.System32));
+
+ // Library should not be found in the assembly directory, but should fall back to the default OS search which includes CWD on Windows
+ success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory));
+ success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory));
+
+ // Library should not be found in application directory
success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.ApplicationDirectory), TestResult.DllNotFound);
success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.ApplicationDirectory), TestResult.ReturnFailure);
+
}
// Calls with null libName input
@@ -134,6 +143,35 @@ public static int Main()
success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.DllNotFound);
success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.ReturnFailure);
+ string suffix = "-in-subdirectory";
+ libName = $"{NativeLibraryToLoad.Name}{suffix}";
+ string subdirectory = Path.Combine(testBinDir, "subdirectory");
+
+ if (!TestLibrary.Utilities.IsMonoLLVMFULLAOT)
+ {
+ // Library should be found in the assembly directory
+ Assembly assemblyInSubdirectory = Assembly.LoadFile(Path.Combine(subdirectory, $"{Path.GetFileNameWithoutExtension(assembly.Location)}{suffix}.dll"));
+ EXPECT(LoadLibraryAdvanced(libName, assemblyInSubdirectory, DllImportSearchPath.AssemblyDirectory));
+ EXPECT(TryLoadLibraryAdvanced(libName, assemblyInSubdirectory, DllImportSearchPath.AssemblyDirectory));
+ }
+
+ if (OperatingSystem.IsWindows())
+ {
+ string currentDirectory = Environment.CurrentDirectory;
+ try
+ {
+ Environment.CurrentDirectory = subdirectory;
+
+ // Library should not be found in the assembly directory, but should fall back to the default OS search which includes CWD on Windows
+ EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory));
+ EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory));
+ }
+ finally
+ {
+ Environment.CurrentDirectory = currentDirectory;
+ }
+ }
+
// -----------------------------------------------
// FreeLibrary Tests
// -----------------------------------------------
diff --git a/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.csproj b/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.csproj
index 51c156e0d9b9e6..47cfe35cd59ecb 100644
--- a/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.csproj
+++ b/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.csproj
@@ -16,4 +16,17 @@
+
+
+
+ $(OutDir)/subdirectory
+ -in-subdirectory
+
+
+
+
+
+
+
+
diff --git a/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibraryToLoad.cs b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibraryToLoad.cs
index 4a61c599961f5a..efc878fd9fc520 100644
--- a/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibraryToLoad.cs
+++ b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibraryToLoad.cs
@@ -27,8 +27,11 @@ public static string GetFileName()
public static string GetFullPath()
{
- Assembly assembly = Assembly.GetExecutingAssembly();
- string directory = Path.GetDirectoryName(assembly.Location);
- return Path.Combine(directory, GetFileName());
+ return Path.Combine(GetDirectory(), GetFileName());
+ }
+
+ public static string GetDirectory()
+ {
+ return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
}
}