Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
25 changes: 18 additions & 7 deletions src/mono/mono/metadata/native-library.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 <code>i:</code>, the comparison of the
* name. If the \p dll name contains the prefix <code>i:</code>, 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
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down
3 changes: 3 additions & 0 deletions src/tests/Common/CoreCLRTestLibrary/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions src/tests/Common/testenvironment.proj
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@
<!-- Mono interpreter -->
<_TestEnvFileLine Condition="'$(RuntimeVariant)' == 'monointerpreter'" Include="set MONO_ENV_OPTIONS=--interpreter" />

<_TestEnvFileLine Condition="'$(RuntimeVariant)' != ''" Include="set DOTNET_RUNTIME_VARIANT=$(RuntimeVariant)" />

<!-- CLR interpreter -->
<_TestEnvFileLine Condition="'$(Scenario)' == 'clrinterpreter'" Include="set COMPlus_Interpret=%2A" /> <!-- %2A is asterisk / wildcard -->
<_TestEnvFileLine Condition="'$(Scenario)' == 'clrinterpreter'" Include="set COMPlus_InterpreterHWIntrinsicsIsSupportedFalse=1" />
Expand All @@ -216,6 +218,8 @@
<!-- Mono interpreter -->
<_TestEnvFileLine Condition="'$(RuntimeVariant)' == 'monointerpreter'" Include="export MONO_ENV_OPTIONS=--interpreter" />

<_TestEnvFileLine Condition="'$(RuntimeVariant)' != ''" Include="export DOTNET_RUNTIME_VARIANT=$(RuntimeVariant)" />

<!-- Hack: Use Mono LLVM JIT when JIT-compiling the non-AOT-compiled parts of the runtime tests -->
<_TestEnvFileLine Condition="'$(RuntimeVariant)' == 'llvmaot'" Include="export MONO_ENV_OPTIONS=--llvm" />

Expand Down
79 changes: 79 additions & 0 deletions src/tests/Interop/DllImportSearchPaths/DllImportSearchPathsTest.cs
Original file line number Diff line number Diff line change
@@ -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<DllNotFoundException>(() => 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);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="*.cs" />
<Compile Include="../NativeLibrary/NativeLibraryToLoad/NativeLibraryToLoad.cs" />
<ProjectReference Include="../NativeLibrary/NativeLibraryToLoad/CMakeLists.txt" />
</ItemGroup>

<Target Name="SetUpSubdirectory" AfterTargets="CopyNativeProjectBinaries">
<PropertyGroup>
<NativeLibrarySubdirectory>$(OutDir)/subdirectory</NativeLibrarySubdirectory>
<FileNameSuffix>-in-subdirectory</FileNameSuffix>
</PropertyGroup>
<ItemGroup>
<_FilesToCopy Include="$(OutDir)/$(TargetName).dll" />
<_FilesToMove Include="$(OutDir)/libNativeLibrary.*" />
<_FilesToMove Include="$(OutDir)/NativeLibrary.*" />
</ItemGroup>
<Copy SourceFiles="@(_FilesToCopy)" DestinationFiles="@(_FilesToCopy -> '$(NativeLibrarySubdirectory)/%(Filename)%(Extension)')" />
<Move SourceFiles="@(_FilesToMove)" DestinationFiles="@(_FilesToMove -> '$(NativeLibrarySubdirectory)/%(Filename)%(Extension)')" />
</Target>
</Project>
42 changes: 40 additions & 2 deletions src/tests/Interop/NativeLibrary/API/NativeLibraryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
// -----------------------------------------------
Expand Down
13 changes: 13 additions & 0 deletions src/tests/Interop/NativeLibrary/API/NativeLibraryTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,17 @@
<ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
<ProjectReference Include="../NativeLibraryToLoad/CMakeLists.txt" />
</ItemGroup>

<Target Name="SetUpSubdirectory" AfterTargets="CopyNativeProjectBinaries">
<PropertyGroup>
<NativeLibrarySubdirectory>$(OutDir)/subdirectory</NativeLibrarySubdirectory>
<FileNameSuffix>-in-subdirectory</FileNameSuffix>
</PropertyGroup>
<ItemGroup>
<AssembliesToCopy Include="$(OutDir)/libNativeLibrary.*" />
<AssembliesToCopy Include="$(OutDir)/NativeLibrary.*" />
<AssembliesToCopy Include="$(OutDir)/$(TargetName).dll" />
</ItemGroup>
<Copy SourceFiles="@(AssembliesToCopy)" DestinationFiles="@(AssembliesToCopy -> '$(NativeLibrarySubdirectory)/%(Filename)$(FileNameSuffix)%(Extension)')" />
</Target>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}