diff --git a/src/coreclr/hosts/corerun/CMakeLists.txt b/src/coreclr/hosts/corerun/CMakeLists.txt index b95f4c87bd878a..c5ce0861651c72 100644 --- a/src/coreclr/hosts/corerun/CMakeLists.txt +++ b/src/coreclr/hosts/corerun/CMakeLists.txt @@ -8,6 +8,9 @@ else(CLR_CMAKE_HOST_WIN32) include(configure.cmake) endif(CLR_CMAKE_HOST_WIN32) +#Required to expose symbols for global symbol discovery. +set(CLR_CMAKE_KEEP_NATIVE_SYMBOLS TRUE) + add_executable_clr(corerun corerun.cpp dotenv.cpp @@ -25,6 +28,8 @@ if(CLR_CMAKE_HOST_WIN32) ) else(CLR_CMAKE_HOST_WIN32) target_link_libraries(corerun ${CMAKE_DL_LIBS}) + # Required to expose symbols for global symbol discovery + target_link_libraries(corerun -rdynamic) # Android implements pthread natively if(NOT CLR_CMAKE_TARGET_ANDROID) diff --git a/src/coreclr/hosts/corerun/corerun.cpp b/src/coreclr/hosts/corerun/corerun.cpp index 67a43e28b20d15..60b5c5522d1857 100644 --- a/src/coreclr/hosts/corerun/corerun.cpp +++ b/src/coreclr/hosts/corerun/corerun.cpp @@ -564,16 +564,13 @@ int MAIN(const int argc, const char_t* argv[]) return exit_code; } -#ifdef TARGET_WINDOWS -// Used by CoreShim to determine running CoreCLR details. -extern "C" __declspec(dllexport) HRESULT __cdecl GetCurrentClrDetails(void** clrInstance, unsigned int* appDomainId) +extern "C" DLL_EXPORT HRESULT CDECL GetCurrentClrDetails(void** clrInstance, unsigned int* appDomainId) { assert(clrInstance != nullptr && appDomainId != nullptr); *clrInstance = CurrentClrInstance; *appDomainId = CurrentAppDomainId; return S_OK; } -#endif // TARGET_WINDOWS // // Self testing for corerun. diff --git a/src/coreclr/hosts/corerun/corerun.hpp b/src/coreclr/hosts/corerun/corerun.hpp index 14cb9ec6580e16..c2f9ae40f07c34 100644 --- a/src/coreclr/hosts/corerun/corerun.hpp +++ b/src/coreclr/hosts/corerun/corerun.hpp @@ -47,8 +47,10 @@ namespace pal } #ifdef TARGET_WINDOWS +#define CDECL __cdecl #include +#define DLL_EXPORT __declspec(dllexport) #define MAIN __cdecl wmain #define W(str) L ## str @@ -316,10 +318,16 @@ class platform_specific_actions final #include #include +#if __GNUC__ >= 4 +#define DLL_EXPORT __attribute__ ((visibility ("default"))) +#else +#define DLL_EXPORT +#endif +#define CDECL #define MAIN main #define W(str) str -#define FAILED(result) (result < 0) - +#define S_OK 0 +#define FAILED(result) (result < S_OK) #if !HAVE_DIRENT_D_TYPE #define DT_UNKNOWN 0 #define DT_DIR 4 @@ -327,6 +335,8 @@ class platform_specific_actions final #define DT_LNK 10 #endif +typedef int HRESULT; + namespace pal { using char_t = char; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 829c2a570ed2b0..c3934de3a9b662 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -327,9 +327,6 @@ Interop\Unix\System.Native\Interop.SchedGetCpu.cs - - Interop\Unix\System.Native\Interop.DynamicLoad.cs - Interop\Unix\System.Native\Interop.Threading.cs diff --git a/src/coreclr/vm/nativelibrarynative.cpp b/src/coreclr/vm/nativelibrarynative.cpp index bce6ea6c036fa0..c4594521cf09f3 100644 --- a/src/coreclr/vm/nativelibrarynative.cpp +++ b/src/coreclr/vm/nativelibrarynative.cpp @@ -70,4 +70,3 @@ extern "C" INT_PTR QCALLTYPE NativeLibrary_GetSymbol(INT_PTR handle, LPCWSTR sym return address; } - diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.DynamicLoad.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.DynamicLoad.cs index 1bcc468f01f6b3..f806b691ae3b95 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.DynamicLoad.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.DynamicLoad.cs @@ -19,5 +19,8 @@ internal unsafe partial class Sys [LibraryImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_FreeLibrary")] internal static partial void FreeLibrary(IntPtr handle); + + [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetDefaultSearchOrderPseudoHandle", SetLastError = true)] + internal static partial IntPtr GetDefaultSearchOrderPseudoHandle(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 8bf268cecd0035..6de9a0d2042d34 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1831,6 +1831,9 @@ Common\Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs + + Common\Interop\Windows\Kernel32\Interop.GetModuleHandle.cs + Common\System\IO\FileSystem.Attributes.Windows.cs @@ -1973,6 +1976,9 @@ Common\Interop\Unix\System.Native\Interop.CopyFile.cs + + Common\Interop\Unix\System.Native\Interop.DynamicLoad.cs + Common\Interop\Unix\System.Native\Interop.ErrNo.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs index 0cd98bb914629d..d95a8c4c22d998 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.ComponentModel; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; @@ -231,5 +232,26 @@ internal static IntPtr LoadLibraryCallbackStub(string libraryName, Assembly asse return resolver(libraryName, assembly, hasDllImportSearchPathFlags ? (DllImportSearchPath?)dllImportSearchPathFlags : null); } + + /// + /// Get a handle that can be used with or to resolve exports from the entry point module. + /// + /// The handle that can be used to resolve exports from the entry point module. + public static IntPtr GetMainProgramHandle() + { + IntPtr result = IntPtr.Zero; +#if TARGET_WINDOWS + result = Interop.Kernel32.GetModuleHandle(null); +#else + result = Interop.Sys.GetDefaultSearchOrderPseudoHandle(); +#endif + // I don't know when a failure case can occur here, but checking for it and throwing an exception + // if we encounter it. + if (result == IntPtr.Zero) + { + throw new Win32Exception(Marshal.GetLastPInvokeError()); + } + return result; + } } } diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index eac47acf63d96a..6fb0760630aea0 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -774,6 +774,7 @@ public MarshalDirectiveException(string? message, System.Exception? inner) { } public static partial class NativeLibrary { public static void Free(System.IntPtr handle) { } + public static System.IntPtr GetMainProgramHandle() { throw null; } public static System.IntPtr GetExport(System.IntPtr handle, string name) { throw null; } public static System.IntPtr Load(string libraryPath) { throw null; } public static System.IntPtr Load(string libraryName, System.Reflection.Assembly assembly, System.Runtime.InteropServices.DllImportSearchPath? searchPath) { throw null; } diff --git a/src/mono/mono/metadata/native-library.c b/src/mono/mono/metadata/native-library.c index a1fc8b47b702dd..68823483fb2fd2 100644 --- a/src/mono/mono/metadata/native-library.c +++ b/src/mono/mono/metadata/native-library.c @@ -757,13 +757,27 @@ netcore_check_alc_cache (MonoAssemblyLoadContext *alc, const char *scope) return result; } +static MonoDl* +netcore_lookup_self_native_handle() +{ + char *error_msg = NULL; + if (!internal_module) + internal_module = mono_dl_open_self (&error_msg); + + if (!internal_module) { + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '__Internal': '%s'.", error_msg); + g_free (error_msg); + } + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Native library found via __Internal."); + return internal_module; +} + static MonoDl * netcore_lookup_native_library (MonoAssemblyLoadContext *alc, MonoImage *image, const char *scope, guint32 flags) { MonoDl *module = NULL; MonoDl *cached; MonoAssembly *assembly = mono_image_get_assembly (image); - char *error_msg = NULL; MONO_REQ_GC_UNSAFE_MODE; @@ -771,18 +785,7 @@ netcore_lookup_native_library (MonoAssemblyLoadContext *alc, MonoImage *image, c // We allow a special name to dlopen from the running process namespace, which is not present in CoreCLR if (strcmp (scope, "__Internal") == 0) { - if (!internal_module) - internal_module = mono_dl_open_self (&error_msg); - module = internal_module; - - if (!module) { - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '__Internal': '%s'.", error_msg); - g_free (error_msg); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Native library found via __Internal: '%s'.", scope); - - return module; + return netcore_lookup_self_native_handle(); } /* @@ -1219,9 +1222,9 @@ ves_icall_System_Runtime_InteropServices_NativeLibrary_FreeLib (gpointer lib, Mo g_hash_table_add (native_library_module_blocklist, module); mono_dl_close (module); } else { - MonoDl raw_module = { { 0 } }; - raw_module.handle = lib; - mono_dl_close (&raw_module); + MonoDl* raw_module = g_new0(MonoDl, 1); + raw_module->handle = lib; + mono_dl_close (raw_module); } leave: diff --git a/src/native/libs/System.Native/entrypoints.c b/src/native/libs/System.Native/entrypoints.c index 9587c9e9b4c852..7b764d5451777c 100644 --- a/src/native/libs/System.Native/entrypoints.c +++ b/src/native/libs/System.Native/entrypoints.c @@ -234,6 +234,7 @@ static const Entry s_sysNative[] = DllImportEntry(SystemNative_LoadLibrary) DllImportEntry(SystemNative_GetProcAddress) DllImportEntry(SystemNative_FreeLibrary) + DllImportEntry(SystemNative_GetDefaultSearchOrderPseudoHandle) DllImportEntry(SystemNative_SchedGetCpu) DllImportEntry(SystemNative_Exit) DllImportEntry(SystemNative_Abort) diff --git a/src/native/libs/System.Native/pal_dynamicload.c b/src/native/libs/System.Native/pal_dynamicload.c index 20ac55859eb1ad..39f6714cc5a1a4 100644 --- a/src/native/libs/System.Native/pal_dynamicload.c +++ b/src/native/libs/System.Native/pal_dynamicload.c @@ -50,3 +50,20 @@ void SystemNative_FreeLibrary(void* handle) { dlclose(handle); } + +#ifdef TARGET_ANDROID +void* SystemNative_GetDefaultSearchOrderPseudoHandle(void) +{ + return (void*)RTLD_DEFAULT; +} +#else +static void* g_defaultSearchOrderPseudoHandle = NULL; +void* SystemNative_GetDefaultSearchOrderPseudoHandle(void) +{ + if (g_defaultSearchOrderPseudoHandle == NULL) + { + g_defaultSearchOrderPseudoHandle = dlopen(NULL, RTLD_LAZY); + } + return g_defaultSearchOrderPseudoHandle; +} +#endif diff --git a/src/native/libs/System.Native/pal_dynamicload.h b/src/native/libs/System.Native/pal_dynamicload.h index 857f45def88eb3..71ce8bf844be4d 100644 --- a/src/native/libs/System.Native/pal_dynamicload.h +++ b/src/native/libs/System.Native/pal_dynamicload.h @@ -11,3 +11,5 @@ PALEXPORT void* SystemNative_LoadLibrary(const char* filename); PALEXPORT void* SystemNative_GetProcAddress(void* handle, const char* symbol); PALEXPORT void SystemNative_FreeLibrary(void* handle); + +PALEXPORT void* SystemNative_GetDefaultSearchOrderPseudoHandle(void); diff --git a/src/tests/Common/CoreCLRTestLibrary/Utilities.cs b/src/tests/Common/CoreCLRTestLibrary/Utilities.cs index ad4d5bac5d3f8f..0ab8a56ce7e2ca 100644 --- a/src/tests/Common/CoreCLRTestLibrary/Utilities.cs +++ b/src/tests/Common/CoreCLRTestLibrary/Utilities.cs @@ -59,6 +59,7 @@ public static bool Verbose } public static bool IsX86 => (RuntimeInformation.ProcessArchitecture == Architecture.X86); + public static bool IsNotX86 => !IsX86; public static bool IsX64 => (RuntimeInformation.ProcessArchitecture == Architecture.X64); public static bool IsArm => (RuntimeInformation.ProcessArchitecture == Architecture.Arm); public static bool IsArm64 => (RuntimeInformation.ProcessArchitecture == Architecture.Arm64); diff --git a/src/tests/Interop/NativeLibrary/API/GetLibraryExportTests.cs b/src/tests/Interop/NativeLibrary/API/GetLibraryExportTests.cs new file mode 100644 index 00000000000000..4f0453dbdf8b0a --- /dev/null +++ b/src/tests/Interop/NativeLibrary/API/GetLibraryExportTests.cs @@ -0,0 +1,96 @@ +// 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.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using Xunit; +using static TestHelpers; + +class GetLibraryExportTests : IDisposable +{ + private readonly IntPtr handle; + + public GetLibraryExportTests() + { + handle = NativeLibrary.Load(NativeLibraryToLoad.GetFullPath()); + } + + [ConditionalFact(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsX86))] + public void GetValidExport_ManualMangling() + { + EXPECT(GetLibraryExport(handle, "_NativeSum@8")); + EXPECT(TryGetLibraryExport(handle, "_NativeSum@8")); + } + + [ConditionalFact(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsNotX86))] + public void GetValidExport() + { + EXPECT(GetLibraryExport(handle, "NativeSum")); + EXPECT(TryGetLibraryExport(handle, "NativeSum")); + } + + [Fact] + public void NullHandle() + { + EXPECT(GetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull); + EXPECT(TryGetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull); + } + + [Fact] + public void NullExport() + { + EXPECT(GetLibraryExport(handle, null), TestResult.ArgumentNull); + EXPECT(TryGetLibraryExport(handle, null), TestResult.ArgumentNull); + } + + [Fact] + public void ExportDoesNotExist() + { + EXPECT(GetLibraryExport(handle, "NonNativeSum"), TestResult.EntryPointNotFound); + EXPECT(TryGetLibraryExport(handle, "NonNativeSum"), TestResult.ReturnFailure); + } + + + public void Dispose() => NativeLibrary.Free(handle); + + static TestResult GetLibraryExport(IntPtr handle, string name) + { + return Run(() => { + IntPtr address = NativeLibrary.GetExport(handle, name); + if (address == IntPtr.Zero) + return TestResult.ReturnNull; + if (RunExportedFunction(address, 1, 1) != 2) + return TestResult.IncorrectEvaluation; + return TestResult.Success; + }); + } + + static TestResult TryGetLibraryExport(IntPtr handle, string name) + { + return Run(() => { + IntPtr address = IntPtr.Zero; + bool success = NativeLibrary.TryGetExport(handle, name, out address); + if (!success) + return TestResult.ReturnFailure; + if (address == IntPtr.Zero) + return TestResult.ReturnNull; + if (RunExportedFunction(address, 1, 1) != 2) + return TestResult.IncorrectEvaluation; + return TestResult.Success; + }); + } + + private static unsafe int RunExportedFunction(IntPtr address, int arg1, int arg2) + { + // We use a delegate here instead of a function pointer to avoid hitting issues + // where Mono AOT doesn't generate the managed->native wrapper and then fails + // when in AOT-only mode. + NativeFunctionWrapper wrapper = Marshal.GetDelegateForFunctionPointer(address); + return wrapper(arg1, arg2); + } + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + private delegate int NativeFunctionWrapper(int arg1, int arg2); +} diff --git a/src/tests/Interop/NativeLibrary/API/GetMainProgramHandleTests.cs b/src/tests/Interop/NativeLibrary/API/GetMainProgramHandleTests.cs new file mode 100644 index 00000000000000..694446fc8a9b98 --- /dev/null +++ b/src/tests/Interop/NativeLibrary/API/GetMainProgramHandleTests.cs @@ -0,0 +1,134 @@ +// 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.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using Xunit; +using static TestHelpers; + +class GetMainProgramHandleTests +{ + // Mobile test runs aren't hosted by corerun, so we don't have a well-known export to test here + [ConditionalFact(nameof(IsHostedByCoreRun))] + public static void CanAccessCoreRunExportFromMainProgramHandle() + { + EXPECT(GetSymbolFromMainProgramHandle("HostExecutable", "GetCurrentClrDetails")); + EXPECT(GetSymbolFromMainProgramHandle("HostExecutable", "NonExistentCoreRunExport"), TestResult.ReturnFailure); + } + + [Fact] + [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst, "Apple platforms load library symbols globally by default.")] + public static void NativeLibraryLoadDoesNotLoadSymbolsGlobally() + { + IntPtr handle = NativeLibrary.Load(NativeLibraryToLoad.GetFullPath()); + try + { + // NativeLibrary does not load symbols globally, so we shouldn't be able to discover symbols from libaries loaded + // with NativeLibary.Load. + EXPECT(GetSymbolFromMainProgramHandle("LocallyLoadedNativeLib", TestLibrary.Utilities.IsX86 ? "_NativeSum@8" : "NativeSum"), TestResult.ReturnFailure); + EXPECT(GetSymbolFromMainProgramHandle("LocallyLoadedNativeLib", "NonNativeSum"), TestResult.ReturnFailure); + + } + finally + { + NativeLibrary.Free(handle); + } + } + + [ConditionalFact(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsNotX86))] + [SkipOnPlatform(TestPlatforms.Windows, "Windows does not have a concept of globally loaded symbols")] + public static void GloballyLoadedLibrarySymbolsVisibleFromMainProgramHandle() + { + // On non-Windows platforms, symbols from globally loaded shared libraries will also be discoverable. + // Globally loading symbols is not the .NET default, so we use a call to dlopen in native code + // with the right flags to test the scenario. + IntPtr handle = LoadLibraryGlobally(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), NativeLibraryToLoad.GetLibraryFileName("GloballyLoadedNativeLibrary"))); + + try + { + EXPECT(GetSymbolFromMainProgramHandle("GloballyLoadedNativeLib", "NativeMultiply")); + } + finally + { + NativeLibrary.Free(handle); + } + } + + [ConditionalFact(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsNotX86))] + [SkipOnPlatform(TestPlatforms.Windows, "Windows does not have a concept of globally loaded symbols")] + public static void InvalidSymbolName_Fails() + { + // On non-Windows platforms, symbols from globally loaded shared libraries will also be discoverable. + // Globally loading symbols is not the .NET default, so we use a call to dlopen in native code + // with the right flags to test the scenario. + IntPtr handle = LoadLibraryGlobally(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), NativeLibraryToLoad.GetLibraryFileName("GloballyLoadedNativeLibrary"))); + + try + { + EXPECT(GetSymbolFromMainProgramHandle("GloballyLoadedNativeLib", "NonNativeMultiply"), TestResult.ReturnFailure); + } + finally + { + NativeLibrary.Free(handle); + } + } + + [ConditionalFact(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsX86))] + [SkipOnPlatform(TestPlatforms.Windows, "Windows does not have a concept of globally loaded symbols")] + public static void GloballyLoadedLibrarySymbolsVisibleFromMainProgramHandle_Mangling() + { + // On non-Windows platforms, symbols from globally loaded shared libraries will also be discoverable. + // Globally loading symbols is not the .NET default, so we use a call to dlopen in native code + // with the right flags to test the scenario. + IntPtr handle = LoadLibraryGlobally(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), NativeLibraryToLoad.GetLibraryFileName("GloballyLoadedNativeLibrary"))); + + try + { + EXPECT(GetSymbolFromMainProgramHandle("GloballyLoadedNativeLib", "_NativeMultiply@8")); + } + finally + { + NativeLibrary.Free(handle); + } + } + + [Fact] + public static void FreeMainProgramHandle() + { + NativeLibrary.Free(NativeLibrary.GetMainProgramHandle()); + Assert.True(true); + } + + public static bool IsHostedByCoreRun { get; } = Process.GetCurrentProcess().MainModule.ModuleName is "corerun" or "corerun.exe"; + + static TestResult GetSymbolFromMainProgramHandle(string scenarioName, string symbolToLoadFromHandle) + { + return Run(() => { + IntPtr moduleHandle = NativeLibrary.GetMainProgramHandle(); + bool success = NativeLibrary.TryGetExport(moduleHandle, symbolToLoadFromHandle, out IntPtr address); + if (!success) + return TestResult.ReturnFailure; + if (address == IntPtr.Zero) + return TestResult.ReturnNull; + return TestResult.Success; + }); + } + + static IntPtr LoadLibraryGlobally(string name) + { + IntPtr handle = LoadLibraryGloballyNative(name); + + if (handle == IntPtr.Zero) + { + throw new Win32Exception(Marshal.GetLastPInvokeError()); + } + + return handle; + + [DllImport("GlobalLoadHelper", EntryPoint = "LoadLibraryGlobally", SetLastError = true)] + static extern IntPtr LoadLibraryGloballyNative(string name); + } +} diff --git a/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.cs b/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.cs index a85e163e997ef6..e46415992e4dd9 100644 --- a/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.cs +++ b/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.cs @@ -1,256 +1,180 @@ // 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.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using Xunit; +using static TestHelpers; -enum TestResult { - Success, - ReturnFailure, - ReturnNull, - IncorrectEvaluation, - ArgumentNull, - ArgumentBad, - DllNotFound, - BadImage, - InvalidOperation, - EntryPointNotFound, - GenericException - }; - -public class NativeLibraryTest +public class NativeLibraryTests : IDisposable { - static string CurrentTest; - static bool Verbose = false; + private readonly Assembly assembly; + private readonly string testBinDir; + private readonly string libFullPath; - public static int Main() + public NativeLibraryTests() { - bool success = true; + assembly = System.Reflection.Assembly.GetExecutingAssembly(); + testBinDir = Path.GetDirectoryName(assembly.Location); + libFullPath = NativeLibraryToLoad.GetFullPath(); + } - Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); - string testBinDir = Path.GetDirectoryName(assembly.Location); - string libFullPath = NativeLibraryToLoad.GetFullPath(); - string libName; - IntPtr handle; + [Fact] + public void LoadLibraryFullPath_NameOnly() + { + string libName = libFullPath; + EXPECT(LoadLibrary_NameOnly(libName)); + EXPECT(TryLoadLibrary_NameOnly(libName)); + } - try - { - // ----------------------------------------------- - // Simple LoadLibrary() API Tests - // ----------------------------------------------- - - // Calls on correct full-path to native lib - libName = libFullPath; - success &= EXPECT(LoadLibrarySimple(libName)); - success &= EXPECT(TryLoadLibrarySimple(libName)); - - // Calls on non-existant file - libName = Path.Combine(testBinDir, "notfound"); - success &= EXPECT(LoadLibrarySimple(libName), TestResult.DllNotFound); - success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ReturnFailure); - - // Calls on an invalid file - libName = Path.Combine(testBinDir, "NativeLibrary.cpp"); - success &= EXPECT(LoadLibrarySimple(libName), - (TestLibrary.Utilities.IsWindows) ? TestResult.BadImage : TestResult.DllNotFound); - success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ReturnFailure); - - // Calls on null input - libName = null; - success &= EXPECT(LoadLibrarySimple(libName), TestResult.ArgumentNull); - success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ArgumentNull); - - // ----------------------------------------------- - // Advanced LoadLibrary() API Tests - // ----------------------------------------------- - - // Advanced LoadLibrary() API Tests - // Calls on correct full-path to native lib - libName = libFullPath; - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null)); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null)); - - // Calls on non-existant file - libName = Path.Combine(testBinDir, "notfound"); - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), TestResult.DllNotFound); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), TestResult.ReturnFailure); - - // Calls on an invalid file - libName = Path.Combine(testBinDir, "NativeLibrary.cpp"); - // The VM can only distinguish BadImageFormatException from DllNotFoundException on Windows. - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), - (TestLibrary.Utilities.IsWindows) ? TestResult.BadImage : TestResult.DllNotFound); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), TestResult.ReturnFailure); - - // Calls on just Native Library name - libName = NativeLibraryToLoad.Name; - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null)); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null)); - - // Calls on Native Library name with correct prefix-suffix - libName = NativeLibraryToLoad.GetFileName(); - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null)); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null)); - - // Calls on full path without prefix-siffix - libName = Path.Combine(testBinDir, NativeLibraryToLoad.Name); - // DllImport doesn't add a prefix if the name is preceeded by a path specification. - // Windows only needs a suffix, but Linux and Mac need both prefix and suffix - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), - (TestLibrary.Utilities.IsWindows) ? TestResult.Success : TestResult.DllNotFound); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), - (TestLibrary.Utilities.IsWindows) ? TestResult.Success : TestResult.ReturnFailure); - - // Check for loading a native binary in the system32 directory. - // The choice of the binary is arbitrary, and may not be available on - // all Windows platforms (ex: Nano server) - libName = "url.dll"; - if (TestLibrary.Utilities.IsWindows && - File.Exists(Path.Combine(Environment.SystemDirectory, libName))) - { - // Calls on a valid library from System32 directory - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.System32)); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.System32)); - - // Calls on a valid library from 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 - success &= EXPECT(LoadLibraryAdvanced(null, assembly, null), TestResult.ArgumentNull); - success &= EXPECT(TryLoadLibraryAdvanced(null, assembly, null), TestResult.ArgumentNull); - - // Calls with null assembly - libName = NativeLibraryToLoad.Name; - success &= EXPECT(LoadLibraryAdvanced(libName, null, null), TestResult.ArgumentNull); - success &= EXPECT(TryLoadLibraryAdvanced(libName, null, null), TestResult.ArgumentNull); - - // Ensure that a lib is not picked up from current directory when - // a different full-path is specified. - libName = Path.Combine(testBinDir, Path.Combine("lib", NativeLibraryToLoad.Name)); - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.DllNotFound); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.ReturnFailure); - - // ----------------------------------------------- - // FreeLibrary Tests - // ----------------------------------------------- - - libName = libFullPath; - handle = NativeLibrary.Load(libName); - - // Valid Free - success &= EXPECT(FreeLibrary(handle)); - - // Double Free - if (TestLibrary.Utilities.IsWindows) - { - // The FreeLibrary() implementation simply calls the appropriate OS API - // with the supplied handle. Not all OSes consistently return an error - // when a library is double-freed. - success &= EXPECT(FreeLibrary(handle), TestResult.InvalidOperation); - } - - // Null Free - success &= EXPECT(FreeLibrary(IntPtr.Zero)); - - // ----------------------------------------------- - // GetLibraryExport Tests - // ----------------------------------------------- - libName = libFullPath; - handle = NativeLibrary.Load(libName); - - // Valid Call (with some hard-coded name mangling) - success &= EXPECT(GetLibraryExport(handle, TestLibrary.Utilities.IsX86 ? "_NativeSum@8" : "NativeSum")); - success &= EXPECT(TryGetLibraryExport(handle, TestLibrary.Utilities.IsX86 ? "_NativeSum@8" : "NativeSum")); - - // Call with null handle - success &= EXPECT(GetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull); - success &= EXPECT(TryGetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull); - - // Call with null string - success &= EXPECT(GetLibraryExport(handle, null), TestResult.ArgumentNull); - success &= EXPECT(TryGetLibraryExport(handle, null), TestResult.ArgumentNull); - - // Call with wrong string - success &= EXPECT(GetLibraryExport(handle, "NonNativeSum"), TestResult.EntryPointNotFound); - success &= EXPECT(TryGetLibraryExport(handle, "NonNativeSum"), TestResult.ReturnFailure); + [Fact] + public void LoadLibraryOnNonExistentFile_NameOnly() + { + string libName = Path.Combine(testBinDir, "notfound"); + EXPECT(LoadLibrary_NameOnly(libName), TestResult.DllNotFound); + EXPECT(TryLoadLibrary_NameOnly(libName), TestResult.ReturnFailure); + } + + [Fact] + public void LoadLibraryOnInvalidFile_NameOnly() + { + string libName = Path.Combine(testBinDir, "NativeLibrary.cpp"); + EXPECT(LoadLibrary_NameOnly(libName), + OperatingSystem.IsWindows() ? TestResult.BadImage : TestResult.DllNotFound); + EXPECT(TryLoadLibrary_NameOnly(libName), TestResult.ReturnFailure); + } - NativeLibrary.Free(handle); - } - catch (Exception e) - { - // Catch any exceptions in NativeLibrary calls directly within this function. - // These calls are used to setup the environment for tests that follow, and are not expected to fail. - // If they do fail (ex: incorrect build environment) fail with an error code, rather than segmentation fault. - Console.WriteLine(String.Format("Unhandled exception {0}", e)); - success = false; - } + [Fact] + public void LoadLibraryFullPath_WithAssembly() + { + string libName = libFullPath; + EXPECT(LoadLibrary_WithAssembly(libName, assembly, null)); + EXPECT(TryLoadLibrary_WithAssembly(libName, assembly, null)); + } - return (success) ? 100 : -100; + [Fact] + public void LoadLibraryOnNonExistentFile_WithAssembly() + { + string libName = Path.Combine(testBinDir, "notfound"); + EXPECT(LoadLibrary_WithAssembly(libName, assembly, null), TestResult.DllNotFound); + EXPECT(TryLoadLibrary_WithAssembly(libName, assembly, null), TestResult.ReturnFailure); } - static bool EXPECT(TestResult actualValue, TestResult expectedValue = TestResult.Success) + [Fact] + public void LoadLibraryOnInvalidFile_WithAssembly() { - if (actualValue == expectedValue) - { - if (Verbose) - Console.WriteLine(String.Format("{0} : {1} : [OK]", CurrentTest, actualValue)); - return true; - } - else - { - Console.WriteLine(String.Format(" {0} : {1} : [FAIL]", CurrentTest, actualValue)); - return false; - } + string libName = Path.Combine(testBinDir, "NativeLibrary.cpp"); + EXPECT(LoadLibrary_WithAssembly(libName, assembly, null), + OperatingSystem.IsWindows() ? TestResult.BadImage : TestResult.DllNotFound); + EXPECT(TryLoadLibrary_WithAssembly(libName, assembly, null), TestResult.ReturnFailure); } - static TestResult Run (Func test) + [Fact] + public void LoadLibraryNameOnly_WithAssembly() { - TestResult result; + string libName = NativeLibraryToLoad.Name; + EXPECT(LoadLibrary_WithAssembly(libName, assembly, null)); + EXPECT(TryLoadLibrary_WithAssembly(libName, assembly, null)); + } - try - { - result = test(); - } - catch (ArgumentNullException) - { - return TestResult.ArgumentNull; - } - catch (ArgumentException) - { - return TestResult.ArgumentBad; - } - catch (DllNotFoundException) - { - return TestResult.DllNotFound; - } - catch (BadImageFormatException) - { - return TestResult.BadImage; - } - catch (InvalidOperationException) - { - return TestResult.InvalidOperation; - } - catch (EntryPointNotFoundException) - { - return TestResult.EntryPointNotFound; - } - catch (Exception) + [Fact] + public void LoadLibraryFileName_WithAssembly() + { + string libName = NativeLibraryToLoad.GetFileName(); + EXPECT(LoadLibrary_WithAssembly(libName, assembly, null)); + EXPECT(TryLoadLibrary_WithAssembly(libName, assembly, null)); + } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void LoadLibraryFullPathWithoutNativePrefixOrSuffix_WithAssembly_Success() + { + // DllImport doesn't add a prefix if the name is preceeded by a path specification. + // Windows only needs a suffix, so adding only the suffix is successful + string libName = Path.Combine(testBinDir, NativeLibraryToLoad.Name); + EXPECT(LoadLibrary_WithAssembly(libName, assembly, null)); + EXPECT(TryLoadLibrary_WithAssembly(libName, assembly, null)); + } + + [Fact] + [PlatformSpecific(~TestPlatforms.Windows)] + public void LoadLibraryFullPathWithoutNativePrefixOrSuffix_WithAssembly_Failure() + { + // DllImport doesn't add a prefix if the name is preceeded by a path specification. + // Linux and Mac need both prefix and suffix + string libName = Path.Combine(testBinDir, NativeLibraryToLoad.Name); + EXPECT(LoadLibrary_WithAssembly(libName, assembly, null), TestResult.DllNotFound); + EXPECT(TryLoadLibrary_WithAssembly(libName, assembly, null), TestResult.ReturnFailure); + } + + public static bool HasKnownLibraryInSystemDirectory => + OperatingSystem.IsWindows() + && File.Exists(Path.Combine(Environment.SystemDirectory, "url.dll")); + + [ConditionalFact(nameof(HasKnownLibraryInSystemDirectory))] + public void LoadSystemLibrary_WithSearchPath() + { + string libName = "url.dll"; + // Calls on a valid library from System32 directory + EXPECT(LoadLibrary_WithAssembly(libName, assembly, DllImportSearchPath.System32)); + EXPECT(TryLoadLibrary_WithAssembly(libName, assembly, DllImportSearchPath.System32)); + + // Calls on a valid library from application directory + EXPECT(LoadLibrary_WithAssembly(libName, assembly, DllImportSearchPath.ApplicationDirectory), TestResult.DllNotFound); + EXPECT(TryLoadLibrary_WithAssembly(libName, assembly, DllImportSearchPath.ApplicationDirectory), TestResult.ReturnFailure); + } + + [Fact] + public void LoadLibrary_NullLibName() + { + EXPECT(LoadLibrary_WithAssembly(null, assembly, null), TestResult.ArgumentNull); + EXPECT(TryLoadLibrary_WithAssembly(null, assembly, null), TestResult.ArgumentNull); + } + + [Fact] + public void LoadLibrary_NullAssembly() + { + string libName = NativeLibraryToLoad.Name; + EXPECT(LoadLibrary_WithAssembly(libName, null, null), TestResult.ArgumentNull); + EXPECT(TryLoadLibrary_WithAssembly(libName, null, null), TestResult.ArgumentNull); + } + + [Fact] + public void LoadLibary_UsesFullPath_EvenWhen_AssemblyDirectory_Specified() + { + string libName = Path.Combine(testBinDir, Path.Combine("lib", NativeLibraryToLoad.Name)); + EXPECT(LoadLibrary_WithAssembly(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.DllNotFound); + EXPECT(TryLoadLibrary_WithAssembly(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.ReturnFailure); + } + + [Fact] + public void Free() + { + string libName = libFullPath; + IntPtr handle = NativeLibrary.Load(libName); + + // Valid Free + EXPECT(FreeLibrary(handle)); + + // Double Free + if (OperatingSystem.IsWindows()) { - return TestResult.GenericException; + // The FreeLibrary() implementation simply calls the appropriate OS API + // with the supplied handle. Not all OSes consistently return an error + // when a library is double-freed. + EXPECT(FreeLibrary(handle), TestResult.InvalidOperation); } - return result; + // Null Free + EXPECT(FreeLibrary(IntPtr.Zero)); } - static TestResult LoadLibrarySimple(string libPath) - { - CurrentTest = String.Format("LoadLibrary({0})", libPath); + public void Dispose() {} + static TestResult LoadLibrary_NameOnly(string libPath) + { IntPtr handle = IntPtr.Zero; TestResult result = Run(() => { @@ -265,10 +189,8 @@ static TestResult LoadLibrarySimple(string libPath) return result; } - static TestResult TryLoadLibrarySimple(string libPath) + static TestResult TryLoadLibrary_NameOnly(string libPath) { - CurrentTest = String.Format("TryLoadLibrary({0})", libPath); - IntPtr handle = IntPtr.Zero; TestResult result = Run(() => { @@ -286,10 +208,8 @@ static TestResult TryLoadLibrarySimple(string libPath) } - static TestResult LoadLibraryAdvanced(string libName, Assembly assembly, DllImportSearchPath? searchPath) + static TestResult LoadLibrary_WithAssembly(string libName, Assembly assembly, DllImportSearchPath? searchPath) { - CurrentTest = String.Format("LoadLibrary({0}, {1}, {2})", libName, assembly, searchPath); - IntPtr handle = IntPtr.Zero; TestResult result = Run(() => { @@ -304,10 +224,8 @@ static TestResult LoadLibraryAdvanced(string libName, Assembly assembly, DllImpo return result; } - static TestResult TryLoadLibraryAdvanced(string libName, Assembly assembly, DllImportSearchPath? searchPath) + static TestResult TryLoadLibrary_WithAssembly(string libName, Assembly assembly, DllImportSearchPath? searchPath) { - CurrentTest = String.Format("TryLoadLibrary({0}, {1}, {2})", libName, assembly, searchPath); - IntPtr handle = IntPtr.Zero; TestResult result = Run(() => { @@ -326,45 +244,9 @@ static TestResult TryLoadLibraryAdvanced(string libName, Assembly assembly, DllI static TestResult FreeLibrary(IntPtr handle) { - CurrentTest = String.Format("FreeLibrary({0})", handle); - return Run(() => { NativeLibrary.Free(handle); return TestResult.Success; }); } - - static TestResult GetLibraryExport(IntPtr handle, string name) - { - CurrentTest = String.Format("GetLibraryExport({0}, {1})", handle, name); - - return Run(() => { - IntPtr address = NativeLibrary.GetExport(handle, name); - if (address == IntPtr.Zero) - return TestResult.ReturnNull; - if (RunExportedFunction(address, 1, 1) != 2) - return TestResult.IncorrectEvaluation; - return TestResult.Success; - }); - } - - static TestResult TryGetLibraryExport(IntPtr handle, string name) - { - CurrentTest = String.Format("TryGetLibraryExport({0}, {1})", handle, name); - - return Run(() => { - IntPtr address = IntPtr.Zero; - bool success = NativeLibrary.TryGetExport(handle, name, out address); - if (!success) - return TestResult.ReturnFailure; - if (address == IntPtr.Zero) - return TestResult.ReturnNull; - if (RunExportedFunction(address, 1, 1) != 2) - return TestResult.IncorrectEvaluation; - return TestResult.Success; - }); - } - - [DllImport(NativeLibraryToLoad.Name)] - static extern int RunExportedFunction(IntPtr address, int arg1, int arg2); } diff --git a/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.csproj b/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.csproj index bff446661b4f35..50c9834e83a168 100644 --- a/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.csproj +++ b/src/tests/Interop/NativeLibrary/API/NativeLibraryTests.csproj @@ -1,6 +1,5 @@ - Exe true diff --git a/src/tests/Interop/NativeLibrary/API/TestHelpers.cs b/src/tests/Interop/NativeLibrary/API/TestHelpers.cs new file mode 100644 index 00000000000000..25663d0dddfeee --- /dev/null +++ b/src/tests/Interop/NativeLibrary/API/TestHelpers.cs @@ -0,0 +1,71 @@ +// 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.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using Xunit; + +enum TestResult +{ + Success, + ReturnFailure, + ReturnNull, + IncorrectEvaluation, + ArgumentNull, + ArgumentBad, + DllNotFound, + BadImage, + InvalidOperation, + EntryPointNotFound, + GenericException +}; + +static class TestHelpers +{ + public static void EXPECT(TestResult actualValue, TestResult expectedValue = TestResult.Success) + { + Assert.Equal(expectedValue, actualValue); + } + + public static TestResult Run (Func test) + { + TestResult result; + + try + { + result = test(); + } + catch (ArgumentNullException) + { + return TestResult.ArgumentNull; + } + catch (ArgumentException) + { + return TestResult.ArgumentBad; + } + catch (DllNotFoundException) + { + return TestResult.DllNotFound; + } + catch (BadImageFormatException) + { + return TestResult.BadImage; + } + catch (InvalidOperationException) + { + return TestResult.InvalidOperation; + } + catch (EntryPointNotFoundException) + { + return TestResult.EntryPointNotFound; + } + catch (Exception) + { + return TestResult.GenericException; + } + + return result; + } +} diff --git a/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/CMakeLists.txt b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/CMakeLists.txt index 8d9c552fac275c..89cae1fd0d9c4d 100644 --- a/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/CMakeLists.txt +++ b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/CMakeLists.txt @@ -1,10 +1,16 @@ project (NativeLibrary) include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") -set(SOURCES NativeLibrary.cpp) # add the shared library -add_library (NativeLibrary SHARED ${SOURCES}) -target_link_libraries(NativeLibrary ${LINK_LIBRARIES_ADDITIONAL}) +add_library (NativeLibrary SHARED NativeLibrary.cpp) -# add the install targets -install (TARGETS NativeLibrary DESTINATION bin) +if (CLR_CMAKE_TARGET_UNIX) + target_link_libraries(NativeLibrary ${LINK_LIBRARIES_ADDITIONAL}) +endif() + +# add the shared library +add_library (GlobalLoadHelper SHARED GlobalLoadHelper.cpp) +target_link_libraries(GlobalLoadHelper ${LINK_LIBRARIES_ADDITIONAL}) + +add_library (GloballyLoadedNativeLibrary SHARED GloballyLoadedNativeLibrary.cpp) +target_link_libraries(GloballyLoadedNativeLibrary ${LINK_LIBRARIES_ADDITIONAL}) diff --git a/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/GlobalLoadHelper.cpp b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/GlobalLoadHelper.cpp new file mode 100644 index 00000000000000..271634668164a1 --- /dev/null +++ b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/GlobalLoadHelper.cpp @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +#include +#include +#ifndef TARGET_WINDOWS +#include +#endif + +extern "C" DLL_EXPORT void* LoadLibraryGlobally(const char* name) +{ +#ifdef TARGET_WINDOWS + // Windows doesn't support global symbol loading. + return NULL; +#else + return dlopen(name, RTLD_GLOBAL | RTLD_LAZY); +#endif +} \ No newline at end of file diff --git a/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/GloballyLoadedNativeLibrary.cpp b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/GloballyLoadedNativeLibrary.cpp new file mode 100644 index 00000000000000..0b8a92491002ca --- /dev/null +++ b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/GloballyLoadedNativeLibrary.cpp @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +#include +#include + +extern "C" DLL_EXPORT int NativeMultiply(int a, int b) +{ + return a * b; +} diff --git a/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibrary.cpp b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibrary.cpp index 6b556c04a93474..99f867e9f7c7da 100644 --- a/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibrary.cpp +++ b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibrary.cpp @@ -2,16 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. #include #include +#ifndef TARGET_WINDOWS +#include +#endif extern "C" DLL_EXPORT int NativeSum(int a, int b) { return a + b; } - -extern "C" DLL_EXPORT int RunExportedFunction(void *function, int arg1, int arg2) -{ - int(*f)(int, int) = reinterpret_cast(function); - return f(arg1, arg2); -} - - diff --git a/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibraryToLoad.cs b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibraryToLoad.cs index 4a61c599961f5a..21dc1ca1c9c986 100644 --- a/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibraryToLoad.cs +++ b/src/tests/Interop/NativeLibrary/NativeLibraryToLoad/NativeLibraryToLoad.cs @@ -12,15 +12,20 @@ public class NativeLibraryToLoad public const string InvalidName = "DoesNotExist"; public static string GetFileName() + { + return GetLibraryFileName(Name); + } + + public static string GetLibraryFileName(string name) { if (OperatingSystem.IsWindows()) - return $"{Name}.dll"; + return $"{name}.dll"; if (OperatingSystem.IsLinux()) - return $"lib{Name}.so"; + return $"lib{name}.so"; if (OperatingSystem.IsMacOS()) - return $"lib{Name}.dylib"; + return $"lib{name}.dylib"; throw new PlatformNotSupportedException(); }