summaryrefslogtreecommitdiff
path: root/src/vm
diff options
context:
space:
mode:
authorSwaroop Sridhar <Swaroop.Sridhar@microsoft.com>2018-11-21 11:42:01 -0800
committerGitHub <noreply@github.com>2018-11-21 11:42:01 -0800
commit175ba1c0794958bb7d006544b87e00675de742fc (patch)
treee5ef7a67f6c11a7407465661155036b958d6beb3 /src/vm
parent5ef00810b53dcb7cbc4f2cb152ca6af971284e82 (diff)
downloadcoreclr-175ba1c0794958bb7d006544b87e00675de742fc.tar.gz
coreclr-175ba1c0794958bb7d006544b87e00675de742fc.tar.bz2
coreclr-175ba1c0794958bb7d006544b87e00675de742fc.zip
Introduce Marshall.LoadLibrary API (#20871)
Implement Native LoadLibrary API This change commits the following changes: 1) Refactoring DllImport code to reuse LodLibrary by search for pInvoke and LoadLibrary cases 2) Implement the new Native Library API in System.Runtime.Interop.Marshall 3) Add tests for the new APIs
Diffstat (limited to 'src/vm')
-rw-r--r--src/vm/assemblynative.cpp2
-rw-r--r--src/vm/dllimport.cpp190
-rw-r--r--src/vm/dllimport.h12
-rw-r--r--src/vm/ecalllist.h6
-rw-r--r--src/vm/marshalnative.cpp62
-rw-r--r--src/vm/marshalnative.h11
6 files changed, 235 insertions, 48 deletions
diff --git a/src/vm/assemblynative.cpp b/src/vm/assemblynative.cpp
index f95a18125d..afa46457d8 100644
--- a/src/vm/assemblynative.cpp
+++ b/src/vm/assemblynative.cpp
@@ -314,7 +314,7 @@ INT_PTR QCALLTYPE AssemblyNative::InternalLoadUnmanagedDllFromPath(LPCWSTR unman
BEGIN_QCALL;
- moduleHandle = NDirect::LoadLibraryFromPath(unmanagedLibraryPath);
+ moduleHandle = NDirect::LoadLibraryFromPath(unmanagedLibraryPath, true);
END_QCALL;
diff --git a/src/vm/dllimport.cpp b/src/vm/dllimport.cpp
index 9ad41c55c8..18f404949a 100644
--- a/src/vm/dllimport.cpp
+++ b/src/vm/dllimport.cpp
@@ -48,11 +48,14 @@
#endif // FEATURE_PREJIT
#include "eventtrace.h"
-
-
#include "clr/fs/path.h"
using namespace clr::fs;
+// The Bit 0x2 has different semantics in DllImportSearchPath and LoadLibraryExA flags.
+// In DllImportSearchPath enum, bit 0x2 represents SearchAssemblyDirectory -- which is performed by CLR.
+// Unlike other bits in this enum, this bit shouldn't be directly passed on to LoadLibrary()
+#define DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY 0x2
+
// remove when we get an updated SDK
#define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100
#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
@@ -6069,7 +6072,6 @@ private:
SString m_message;
}; // class LoadLibErrorTracker
-// Local helper function to load a library.
// Load the library directly. On Unix systems, don't register it yet with PAL.
// * External callers like AssemblyNative::InternalLoadUnmanagedDllFromPath() and the upcoming
// System.Runtime.Interop.Marshall.LoadLibrary() need the raw system handle
@@ -6132,14 +6134,18 @@ bool NDirect::s_fSecureLoadLibrarySupported = false;
#endif // !FEATURE_PAL
// static
-NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath)
+NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError)
{
STANDARD_VM_CONTRACT;
+ if (libraryPath == NULL)
+ COMPlusThrowArgumentNull(W("libraryPath"), W("ArgumentNull_String"));
+
LoadLibErrorTracker errorTracker;
const NATIVE_LIBRARY_HANDLE hmod =
LocalLoadLibraryHelper(libraryPath, GetLoadWithAlteredSearchPathFlag(), &errorTracker);
- if (hmod == nullptr)
+
+ if (throwOnError && (hmod == nullptr))
{
SString libraryPathSString(libraryPath);
errorTracker.Throw(libraryPathSString);
@@ -6147,8 +6153,133 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath)
return hmod;
}
-/* static */
-NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName)
+// static
+NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly *callingAssembly,
+ BOOL hasDllImportSearchFlag, DWORD dllImportSearchFlag,
+ BOOL throwOnError)
+{
+ STANDARD_VM_CONTRACT;
+
+ LoadLibErrorTracker errorTracker;
+
+ if (libraryName == NULL)
+ COMPlusThrowArgumentNull(W("libraryName"), W("ArgumentNull_String"));
+
+ if (callingAssembly == NULL)
+ COMPlusThrowArgumentNull(W("callingAssembly"), W("ArgumentNull_Assembly"));
+
+ // First checks if a default DllImportSearchPathFlag was passed in, if so, use that value.
+ // Otherwise checks if the assembly has the DefaultDllImportSearchPathsAttribute attribute. If so, use that value.
+ BOOL searchAssemblyDirectory = TRUE;
+ DWORD dllImportSearchPathFlag = 0;
+
+ if (hasDllImportSearchFlag)
+ {
+ dllImportSearchPathFlag = dllImportSearchFlag & ~DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
+ searchAssemblyDirectory = dllImportSearchFlag & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
+
+ }
+ else
+ {
+ Module * pModule = callingAssembly->GetManifestModule();
+
+ if (pModule->HasDefaultDllImportSearchPathsAttribute())
+ {
+ dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
+ searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory();
+ }
+ }
+
+ NATIVE_LIBRARY_HANDLE hmod =
+ LoadLibraryModuleBySearch(callingAssembly, searchAssemblyDirectory, dllImportSearchPathFlag, &errorTracker, libraryName);
+
+ if (throwOnError && (hmod == nullptr))
+ {
+ SString libraryPathSString(libraryName);
+ errorTracker.Throw(libraryPathSString);
+ }
+
+ return hmod;
+}
+
+// static
+NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker, PCWSTR wszLibName)
+{
+ STANDARD_VM_CONTRACT;
+
+ // First checks if the method has DefaultDllImportSearchPathsAttribute. If so, use that value.
+ // Otherwise checks if the assembly has the attribute. If so, use that value.
+ BOOL searchAssemblyDirectory = TRUE;
+ DWORD dllImportSearchPathFlag = 0;
+
+ if (pMD->HasDefaultDllImportSearchPathsAttribute())
+ {
+ dllImportSearchPathFlag = pMD->DefaultDllImportSearchPathsAttributeCachedValue();
+ searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory();
+ }
+ else
+ {
+ Module * pModule = pMD->GetModule();
+
+ if (pModule->HasDefaultDllImportSearchPathsAttribute())
+ {
+ dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
+ searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory();
+ }
+ }
+
+ Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
+ return LoadLibraryModuleBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlag, pErrorTracker, wszLibName);
+}
+
+// static
+void NDirect::FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle)
+{
+ STANDARD_VM_CONTRACT;
+
+ // FreeLibrary doesn't throw if the input is null.
+ // This avoids further null propagation/check while freeing resources (ex: in finally blocks)
+ if (handle == NULL)
+ return;
+
+#ifndef FEATURE_PAL
+ BOOL retVal = FreeLibrary(handle);
+#else // !FEATURE_PAL
+ BOOL retVal = PAL_FreeLibraryDirect(handle);
+#endif // !FEATURE_PAL
+
+ if (retVal == 0)
+ COMPlusThrow(kInvalidOperationException, W("Arg_InvalidOperationException"));
+}
+
+//static
+INT_PTR NDirect::GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (handle == NULL)
+ COMPlusThrowArgumentNull(W("handle"), W("Arg_InvalidHandle"));
+
+ if (symbolName == NULL)
+ COMPlusThrowArgumentNull(W("symbolName"), W("ArgumentNull_String"));
+
+ MAKE_UTF8PTR_FROMWIDE(lpstr, symbolName);
+
+#ifndef FEATURE_PAL
+ INT_PTR address = reinterpret_cast<INT_PTR>(GetProcAddress((HMODULE)handle, lpstr));
+ if ((address == NULL) && throwOnError)
+ COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDR_WIN_DLL, symbolName);
+#else // !FEATURE_PAL
+ INT_PTR address = reinterpret_cast<INT_PTR>(PAL_GetProcAddressDirect((NATIVE_LIBRARY_HANDLE)handle, lpstr));
+ if ((address == NULL) && throwOnError)
+ COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDR_UNIX_SO, symbolName);
+#endif // !FEATURE_PAL
+
+ return address;
+}
+
+// static
+NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, PCWSTR wszLibName)
{
STANDARD_VM_CONTRACT;
//Dynamic Pinvoke Support:
@@ -6376,12 +6507,14 @@ static void DetermineLibNameVariations(const WCHAR** libNameVariations, int* num
#endif // FEATURE_PAL
// Search for the library and variants of its name in probing directories.
-NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName)
+//static
+NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssembly,
+ BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlag,
+ LoadLibErrorTracker * pErrorTracker, LPCWSTR wszLibName)
{
STANDARD_VM_CONTRACT;
-
+
NATIVE_LIBRARY_HANDLE hmod = NULL;
- AppDomain* pDomain = GetAppDomain();
#if defined(FEATURE_CORESYSTEM) && !defined(PLATFORM_UNIX)
// Try to go straight to System32 for Windows API sets. This is replicating quick check from
@@ -6396,9 +6529,10 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD
}
#endif // FEATURE_CORESYSTEM && !FEATURE_PAL
+ AppDomain* pDomain = GetAppDomain();
DWORD loadWithAlteredPathFlags = GetLoadWithAlteredSearchPathFlag();
bool libNameIsRelativePath = Path::IsRelative(wszLibName);
- DWORD dllImportSearchPathFlag = 0;
+
// P/Invokes are often declared with variations on the actual library name.
// For example, it's common to leave off the extension/suffix of the library
// even if it has one, or to leave off a prefix like "lib" even if it has one
@@ -6419,31 +6553,6 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD
return hmod;
}
- // First checks if the method has DefaultDllImportSearchPathsAttribute. If method has the attribute
- // then dllImportSearchPathFlag is set to its value.
- // Otherwise checks if the assembly has the attribute.
- // If assembly has the attribute then flag is set to its value.
- BOOL searchAssemblyDirectory = TRUE;
- BOOL attributeIsFound = FALSE;
-
- if (pMD->HasDefaultDllImportSearchPathsAttribute())
- {
- dllImportSearchPathFlag = pMD->DefaultDllImportSearchPathsAttributeCachedValue();
- searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory();
- attributeIsFound = TRUE;
- }
- else
- {
- Module * pModule = pMD->GetModule();
-
- if (pModule->HasDefaultDllImportSearchPathsAttribute())
- {
- dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
- searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory();
- attributeIsFound = TRUE;
- }
- }
-
if (!libNameIsRelativePath)
{
DWORD flags = loadWithAlteredPathFlags;
@@ -6460,10 +6569,9 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD
return hmod;
}
}
- else if (searchAssemblyDirectory)
+ else if ((callingAssembly != nullptr) && searchAssemblyDirectory)
{
- Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
- hmod = LoadFromPInvokeAssemblyDirectory(pAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
+ hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
if (hmod != NULL)
{
return hmod;
@@ -6547,8 +6655,6 @@ HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracke
hmod = pDomain->FindUnmanagedImageInCache(wszLibName);
if (hmod != NULL)
{
- // AppDomain caches the PAL_registered handles
- // So, no need to PAL_Register the handle obtained from the cache
return hmod.Extract();
}
@@ -6574,7 +6680,7 @@ HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracke
hmod = PAL_RegisterLibraryDirect(hmod, wszLibName);
#endif // FEATURE_PAL
}
- }
+ }
if (hmod != NULL)
{
diff --git a/src/vm/dllimport.h b/src/vm/dllimport.h
index 05336b43c6..2f25e59570 100644
--- a/src/vm/dllimport.h
+++ b/src/vm/dllimport.h
@@ -5,9 +5,6 @@
// File: DllImport.h
//
-//
-
-
#ifndef __dllimport_h__
#define __dllimport_h__
@@ -77,9 +74,13 @@ public:
static HRESULT HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs);
static LPVOID NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod);
- static NATIVE_LIBRARY_HANDLE LoadLibraryFromPath(LPCWSTR libraryPath);
+ static NATIVE_LIBRARY_HANDLE LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError);
+ static NATIVE_LIBRARY_HANDLE LoadLibraryByName(LPCWSTR name, Assembly *callingAssembly,
+ BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag,
+ BOOL throwOnError);
static HINSTANCE LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker *pErrorTracker);
-
+ static void FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle);
+ static INT_PTR GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError);
static VOID NDirectLink(NDirectMethodDesc *pMD);
@@ -125,6 +126,7 @@ private:
static NATIVE_LIBRARY_HANDLE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker);
static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName);
static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName);
+ static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(Assembly *callingAssembly, BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlag, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName);
#if !defined(FEATURE_PAL)
// Indicates if the OS supports the new secure LoadLibraryEx flags introduced in KB2533623
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 9c8ef0b9b4..f7c5a791c3 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -863,6 +863,12 @@ FCFuncStart(gInteropMarshalFuncs)
FCFuncElement("GetExceptionForHRInternal", MarshalNative::GetExceptionForHR)
FCFuncElement("GetDelegateForFunctionPointerInternal", MarshalNative::GetDelegateForFunctionPointerInternal)
FCFuncElement("GetFunctionPointerForDelegateInternal", MarshalNative::GetFunctionPointerForDelegateInternal)
+
+ QCFuncElement("LoadLibraryFromPath", MarshalNative::LoadLibraryFromPath)
+ QCFuncElement("LoadLibraryByName", MarshalNative::LoadLibraryByName)
+ QCFuncElement("FreeNativeLibrary", MarshalNative::FreeNativeLibrary)
+ QCFuncElement("GetNativeLibraryExport", MarshalNative::GetNativeLibraryExport)
+
#ifdef FEATURE_COMINTEROP
FCFuncElement("GetHRForException", MarshalNative::GetHRForException)
FCFuncElement("GetHRForException_WinRT", MarshalNative::GetHRForException_WinRT)
diff --git a/src/vm/marshalnative.cpp b/src/vm/marshalnative.cpp
index a356900756..117b66d6cb 100644
--- a/src/vm/marshalnative.cpp
+++ b/src/vm/marshalnative.cpp
@@ -923,6 +923,68 @@ FCIMPL1(int, MarshalNative::GetHRForException_WinRT, Object* eUNSAFE)
}
FCIMPLEND
+// static
+INT_PTR QCALLTYPE MarshalNative::LoadLibraryFromPath(LPCWSTR path, BOOL throwOnError)
+{
+ QCALL_CONTRACT;
+
+ NATIVE_LIBRARY_HANDLE handle = nullptr;
+
+ BEGIN_QCALL;
+
+ handle = NDirect::LoadLibraryFromPath(path, throwOnError);
+
+ END_QCALL;
+
+ return reinterpret_cast<INT_PTR>(handle);
+}
+
+// static
+INT_PTR QCALLTYPE MarshalNative::LoadLibraryByName(LPCWSTR name, QCall::AssemblyHandle callingAssembly,
+ BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag,
+ BOOL throwOnError)
+{
+ QCALL_CONTRACT;
+
+ NATIVE_LIBRARY_HANDLE handle = nullptr;
+ Assembly *pAssembly = (callingAssembly != NULL) ? callingAssembly->GetAssembly() : NULL;
+
+ BEGIN_QCALL;
+
+ handle = NDirect::LoadLibraryByName(name, pAssembly, hasDllImportSearchPathFlag, dllImportSearchPathFlag, throwOnError);
+
+ END_QCALL;
+
+ return reinterpret_cast<INT_PTR>(handle);
+}
+
+// static
+void QCALLTYPE MarshalNative::FreeNativeLibrary(INT_PTR handle)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ NDirect::FreeNativeLibrary((NATIVE_LIBRARY_HANDLE) handle);
+
+ END_QCALL;
+}
+
+//static
+INT_PTR QCALLTYPE MarshalNative::GetNativeLibraryExport(INT_PTR handle, LPCWSTR symbolName, BOOL throwOnError)
+{
+ QCALL_CONTRACT;
+
+ INT_PTR address = NULL;
+
+ BEGIN_QCALL;
+
+ address = NDirect::GetNativeLibraryExport((NATIVE_LIBRARY_HANDLE)handle, symbolName, throwOnError);
+
+ END_QCALL;
+
+ return address;
+}
#ifdef FEATURE_COMINTEROP
diff --git a/src/vm/marshalnative.h b/src/vm/marshalnative.h
index 25c1dc3ab9..9b6aa2cf9a 100644
--- a/src/vm/marshalnative.h
+++ b/src/vm/marshalnative.h
@@ -85,6 +85,17 @@ public:
static FCDECL2(Object*, GetDelegateForFunctionPointerInternal, LPVOID FPtr, ReflectClassBaseObject* refTypeUNSAFE);
static FCDECL1(LPVOID, GetFunctionPointerForDelegateInternal, Object* refDelegateUNSAFE);
+
+ //====================================================================
+ // These methods provide the native callbacks for library loading APIs
+ //====================================================================
+ static INT_PTR QCALLTYPE LoadLibraryFromPath(LPCWSTR path, BOOL throwOnError);
+ static INT_PTR QCALLTYPE LoadLibraryByName(LPCWSTR name, QCall::AssemblyHandle callingAssembly,
+ BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag,
+ BOOL throwOnError);
+ static void QCALLTYPE FreeNativeLibrary(INT_PTR handle);
+ static INT_PTR QCALLTYPE GetNativeLibraryExport(INT_PTR handle, LPCWSTR symbolName, BOOL throwOnError);
+
#ifdef FEATURE_COMINTEROP
//====================================================================
// map GUID to Type