/* static function declarations ***********************************************/
+template<class TChar> bool LOADVerifyLibraryPath(const TChar *libraryPath);
+bool LOADConvertLibraryPathWideStringToMultibyteString(
+ LPCWSTR wideLibraryPath,
+ CHAR (&multibyteLibraryPath)[MAX_LONGPATH],
+ INT *multibyteLibraryPathLengthRef);
+
static BOOL LOADValidateModule(MODSTRUCT *module);
static LPWSTR LOADGetModuleFileName(MODSTRUCT *module);
+static HMODULE LOADLoadLibraryDirect(LPCSTR libraryNameOrPath, bool setLastError);
+static HMODULE LOADRegisterLibraryDirect(HMODULE dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic);
static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic);
static void LOAD_SEH_CallDllMain(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved);
static MODSTRUCT *LOADAllocModule(void *dl_handle, LPCSTR name);
(lpLibFileName)?lpLibFileName:"NULL",
(lpLibFileName)?lpLibFileName:"NULL");
- if (NULL == lpLibFileName)
+ if (!LOADVerifyLibraryPath(lpLibFileName))
{
- ERROR("lpLibFileName is NULL;Exit.\n");
- SetLastError(ERROR_MOD_NOT_FOUND);
- goto Done;
- }
-
- if (lpLibFileName[0]=='\0')
- {
- ERROR("can't load library with NULL file name...\n");
- SetLastError(ERROR_INVALID_PARAMETER);
goto Done;
}
lpLibFileName?lpLibFileName:W16_NULLSTRING,
lpLibFileName?lpLibFileName:W16_NULLSTRING);
- if (NULL == lpLibFileName)
+ if (!LOADVerifyLibraryPath(lpLibFileName))
{
- ERROR("lpLibFileName is NULL;Exit.\n");
- SetLastError(ERROR_MOD_NOT_FOUND);
goto done;
}
- if (lpLibFileName[0]==0)
+ if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
{
- ERROR("Can't load library with NULL file name...\n");
- SetLastError(ERROR_INVALID_PARAMETER);
goto done;
}
/* do the Dos/Unix conversion on our own copy of the name */
+ FILEDosToUnixPathA(lpstr);
- name_length = WideCharToMultiByte(CP_ACP, 0, lpLibFileName, -1, lpstr,
- MAX_LONGPATH, NULL, NULL);
- if (name_length == 0)
+ /* let LOADLoadLibrary call SetLastError in case of failure */
+ hModule = LOADLoadLibrary(lpstr, TRUE);
+
+done:
+ LOGEXIT("LoadLibraryExW returns HMODULE %p\n", hModule);
+ PERF_EXIT(LoadLibraryExW);
+ return hModule;
+}
+
+/*
+Function:
+LoadLibraryDirect
+
+Loads a library using a system call, without registering the library with the module list.
+
+Returns the system handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
+*/
+HMODULE
+PALAPI
+PAL_LoadLibraryDirect(
+ IN LPCWSTR lpLibFileName)
+{
+ CHAR lpstr[MAX_LONGPATH];
+ INT name_length;
+ HMODULE hModule = NULL;
+
+ PERF_ENTRY(LoadLibraryDirect);
+ ENTRY("LoadLibraryDirect (lpLibFileName=%p (%S)) \n",
+ lpLibFileName?lpLibFileName:W16_NULLSTRING,
+ lpLibFileName?lpLibFileName:W16_NULLSTRING);
+
+ if (!LOADVerifyLibraryPath(lpLibFileName))
+ {
+ goto done;
+ }
+
+ if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
{
- DWORD dwLastError = GetLastError();
- if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
- {
- ERROR("lpLibFileName is larger than MAX_LONGPATH (%d)!\n", MAX_LONGPATH);
- }
- else
- {
- ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
- }
- SetLastError(ERROR_INVALID_PARAMETER);
goto done;
}
+ /* do the Dos/Unix conversion on our own copy of the name */
FILEDosToUnixPathA(lpstr);
- /* let LOADLoadLibrary call SetLastError in case of failure */
- hModule = LOADLoadLibrary(lpstr, TRUE);
+ /* let LOADLoadLibraryDirect call SetLastError in case of failure */
+ hModule = LOADLoadLibraryDirect(lpstr, true /* setLastError */);
done:
- LOGEXIT("LoadLibraryExW returns HMODULE %p\n", hModule);
- PERF_EXIT(LoadLibraryExW);
+ LOGEXIT("LoadLibraryDirect returns HMODULE %p\n", hModule);
+ PERF_EXIT(LoadLibraryDirect);
+ return hModule;
+}
+
+/*
+Function:
+RegisterLibraryDirect
+
+Registers a system handle to a loaded library with the module list.
+
+Returns a PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
+*/
+HMODULE
+PALAPI
+PAL_RegisterLibraryDirect(
+ IN HMODULE dl_handle,
+ IN LPCWSTR lpLibFileName)
+{
+ CHAR lpstr[MAX_LONGPATH];
+ INT name_length;
+ HMODULE hModule = NULL;
+
+ PERF_ENTRY(RegisterLibraryDirect);
+ ENTRY("RegisterLibraryDirect (lpLibFileName=%p (%S)) \n",
+ lpLibFileName ? lpLibFileName : W16_NULLSTRING,
+ lpLibFileName ? lpLibFileName : W16_NULLSTRING);
+
+ if (!LOADVerifyLibraryPath(lpLibFileName))
+ {
+ goto done;
+ }
+
+ if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
+ {
+ goto done;
+ }
+
+ /* do the Dos/Unix conversion on our own copy of the name */
+ FILEDosToUnixPathA(lpstr);
+
+ /* let LOADRegisterLibraryDirect call SetLastError in case of failure */
+ LockModuleList();
+ hModule = LOADRegisterLibraryDirect(dl_handle, lpstr, true /* fDynamic */);
+ UnlockModuleList();
+
+done:
+ LOGEXIT("RegisterLibraryDirect returns HMODULE %p\n", hModule);
+ PERF_EXIT(RegisterLibraryDirect);
return hModule;
}
/* Static function definitions ************************************************/
+// Checks the library path for null or empty string. On error, calls SetLastError() and returns false.
+template<class TChar>
+bool LOADVerifyLibraryPath(const TChar *libraryPath)
+{
+ if (libraryPath == nullptr)
+ {
+ ERROR("libraryPath is null\n");
+ SetLastError(ERROR_MOD_NOT_FOUND);
+ return false;
+ }
+ if (libraryPath[0] == '\0')
+ {
+ ERROR("libraryPath is empty\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+ return true;
+}
+
+// Converts the wide char library path string into a multibyte-char string. On error, calls SetLastError() and returns false.
+bool LOADConvertLibraryPathWideStringToMultibyteString(
+ LPCWSTR wideLibraryPath,
+ CHAR(&multibyteLibraryPath)[MAX_LONGPATH],
+ INT *multibyteLibraryPathLengthRef)
+{
+ _ASSERTE(wideLibraryPath != nullptr);
+ _ASSERTE(multibyteLibraryPathLengthRef != nullptr);
+
+ *multibyteLibraryPathLengthRef = WideCharToMultiByte(CP_ACP, 0, wideLibraryPath, -1, multibyteLibraryPath,
+ MAX_LONGPATH, nullptr, nullptr);
+ if (*multibyteLibraryPathLengthRef == 0)
+ {
+ DWORD dwLastError = GetLastError();
+ if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
+ {
+ ERROR("wideLibraryPath converted to a multibyte string is longer than MAX_LONGPATH (%d)!\n", MAX_LONGPATH);
+ }
+ else
+ {
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ }
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+ return true;
+}
+
/*++
Function :
LOADValidateModule
return module;
}
-/*++
-Function :
- LOADLoadLibrary [internal]
-
- implementation of LoadLibrary (for use by the A/W variants)
+/*
+Function:
+ LOADLoadLibraryDirect [internal]
-Parameters :
- LPSTR shortAsciiName : name of module as specified to LoadLibrary
+ Loads a library using a system call, without registering the library with the module list.
- BOOL fDynamic : TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary
-
-Return value :
- handle to loaded module
+Parameters:
+ LPCSTR libraryNameOrPath: The library to load.
+ bool setLastError: True to set the last error upon failure, false otherwise.
---*/
-static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic)
+Return value:
+ System handle to the loaded library, or nullptr upon failure (error is set via SetLastError() if 'setLastError' is true).
+*/
+static HMODULE LOADLoadLibraryDirect(LPCSTR libraryNameOrPath, bool setLastError)
{
- CHAR fullLibraryName[MAX_LONGPATH];
- MODSTRUCT *module = NULL;
- void *dl_handle = NULL;
- DWORD dwError;
- DWORD retval;
-
- // Check whether we have been requested to load 'libc'. If that's the case then use the
- // full name of the library that is defined in <gnu/lib-names.h> by the LIBC_SO constant.
- // The problem is that calling dlopen("libc.so") will fail for libc even thought it works
- // for other libraries. The reason is that libc.so is just linker script (i.e. a test file).
- // As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO.
- if (strcmp(shortAsciiName, LIBC_NAME_WITHOUT_EXTENSION) == 0)
- {
-#if defined(__APPLE__)
- shortAsciiName = "libc.dylib";
-#elif defined(__FreeBSD__)
- shortAsciiName = FREEBSD_LIBC;
-#else
- shortAsciiName = LIBC_SO;
-#endif
- }
-
- LockModuleList();
+ _ASSERTE(libraryNameOrPath != nullptr);
+ _ASSERTE(libraryNameOrPath[0] != '\0');
- // See if file can be dlopen()ed; this should work even if it's already loaded
+ HMODULE dl_handle = dlopen(libraryNameOrPath, RTLD_LAZY);
+ if (dl_handle != nullptr)
{
- // See GetProcAddress for an explanation why we leave the PAL.
- PAL_LeaveHolder holder;
-
- // 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
- // (both of these are done typically to smooth over cross-platform differences).
- // We try to dlopen with such variations on the original.
- const char* const formatStrings[4] = // used with args: PAL_SHLIB_PREFIX, shortAsciiName, PAL_SHLIB_SUFFIX
- {
- "%s%s%s", // prefix+name+suffix
- "%.0s%s%.0s", // name
- "%.0s%s%s", // name+suffix
- "%s%s%.0s", // prefix+name
- };
- const int skipPrefixing = strchr(shortAsciiName, '/') != NULL; // skip prefixing if the name is actually a path
- for (int i = 0; i < 4; i++)
- {
- if (skipPrefixing && (i == 0 || i == 3)) // 0th and 3rd strings include prefixes
- continue;
-
- if (!dl_handle &&
- snprintf(fullLibraryName, MAX_LONGPATH, formatStrings[i], PAL_SHLIB_PREFIX, shortAsciiName, PAL_SHLIB_SUFFIX) < MAX_LONGPATH &&
- ((dl_handle = dlopen(fullLibraryName, RTLD_LAZY | RTLD_NOLOAD)) ||
- (dl_handle = dlopen(fullLibraryName, RTLD_LAZY))))
- {
- shortAsciiName = fullLibraryName;
- break;
- }
- }
+ TRACE("dlopen() found module %s\n", libraryNameOrPath);
}
-
- if (!dl_handle)
+ else if (setLastError)
{
- WARN("dlopen() failed; dlerror says '%s'\n", dlerror());
+ WARN("dlopen() failed; dlerror says '%s'\n", dlerror());
SetLastError(ERROR_MOD_NOT_FOUND);
- goto done;
}
- TRACE("dlopen() found module %s\n", shortAsciiName);
+
+ return dl_handle;
+}
+
+/*
+Function:
+ LOADRegisterLibraryDirect [internal]
+
+ Registers a system handle to a loaded library with the module list.
+
+Parameters:
+ HMODULE dl_handle: System handle to the loaded library.
+ LPCSTR libraryNameOrPath: The library that was loaded.
+ BOOL fDynamic: TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary.
+
+Return value:
+ PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
+*/
+static HMODULE LOADRegisterLibraryDirect(HMODULE dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic)
+{
+ _ASSERTE(dl_handle != nullptr);
+ _ASSERTE(libraryNameOrPath != nullptr);
+ _ASSERTE(libraryNameOrPath[0] != '\0');
+
+ MODSTRUCT *module;
+ DWORD dwError;
#if !RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
/* search module list for a match. */
/* found the handle. increment the refcount and return the
existing module structure */
TRACE("Found matching module %p for module name %s\n",
- module, shortAsciiName);
+ module, libraryNameOrPath);
if (module->refcount != -1)
module->refcount++;
dlclose(dl_handle);
- goto done;
+ return module;
}
module = module->next;
} while (module != &exe_module);
#endif
- TRACE("Module doesn't exist : creating %s.\n", shortAsciiName);
- module = LOADAllocModule(dl_handle, shortAsciiName);
+ TRACE("Module doesn't exist : creating %s.\n", libraryNameOrPath);
+ module = LOADAllocModule(dl_handle, libraryNameOrPath);
if (NULL == module)
{
ERROR("couldn't create new module\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
dlclose(dl_handle);
- goto done;
+ return nullptr;
}
/* Add the new module on to the end of the list */
PREGISTER_MODULE registerModule = (PREGISTER_MODULE)dlsym(module->dl_handle, "PAL_RegisterModule");
if (registerModule)
{
- module->hinstance = registerModule(shortAsciiName);
+ module->hinstance = registerModule(libraryNameOrPath);
}
else
{
}
}
+ BOOL dllMainRetVal;
{
#if !_NO_DEBUG_MESSAGES_
/* reset ENTRY nesting level back to zero while inside the callback... */
// This module may be foreign to our PAL, so leave our PAL.
// If it depends on us, it will re-enter.
PAL_LeaveHolder holder;
- retval = module->pDllMain(module->hinstance, DLL_PROCESS_ATTACH, fDynamic ? NULL : (LPVOID)-1);
+ dllMainRetVal = module->pDllMain(module->hinstance, DLL_PROCESS_ATTACH, fDynamic ? NULL : (LPVOID)-1);
}
#if !_NO_DEBUG_MESSAGES_
}
// If DlMain(DLL_PROCESS_ATTACH) returns FALSE, we must immediately unload the module
- if (!retval)
+ if (!dllMainRetVal)
{
ERROR("DllMain returned FALSE; unloading module.\n");
module->pDllMain = NULL;
FreeLibrary((HMODULE)module);
SetLastError(ERROR_DLL_INIT_FAILED);
module = NULL;
- goto done;
+ return nullptr;
}
}
else
TRACE("Module does not contain a DllMain function.\n");
}
+ return module;
+}
+
+/*++
+Function :
+ LOADLoadLibrary [internal]
+
+ implementation of LoadLibrary (for use by the A/W variants)
+
+Parameters :
+ LPSTR shortAsciiName : name of module as specified to LoadLibrary
+
+ BOOL fDynamic : TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary
+
+Return value :
+ handle to loaded module
+
+--*/
+static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic)
+{
+ CHAR fullLibraryName[MAX_LONGPATH];
+ HMODULE module = NULL;
+ HMODULE dl_handle = NULL;
+
+ // Check whether we have been requested to load 'libc'. If that's the case then use the
+ // full name of the library that is defined in <gnu/lib-names.h> by the LIBC_SO constant.
+ // The problem is that calling dlopen("libc.so") will fail for libc even thought it works
+ // for other libraries. The reason is that libc.so is just linker script (i.e. a test file).
+ // As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO.
+ if (strcmp(shortAsciiName, LIBC_NAME_WITHOUT_EXTENSION) == 0)
+ {
+#if defined(__APPLE__)
+ shortAsciiName = "libc.dylib";
+#elif defined(__FreeBSD__)
+ shortAsciiName = FREEBSD_LIBC;
+#else
+ shortAsciiName = LIBC_SO;
+#endif
+ }
+
+ LockModuleList();
+
+ // See if file can be dlopen()ed; this should work even if it's already loaded
+ {
+ // See GetProcAddress for an explanation why we leave the PAL.
+ PAL_LeaveHolder holder;
+
+ // 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
+ // (both of these are done typically to smooth over cross-platform differences).
+ // We try to dlopen with such variations on the original.
+ const char* const formatStrings[4] = // used with args: PAL_SHLIB_PREFIX, shortAsciiName, PAL_SHLIB_SUFFIX
+ {
+ "%s%s%s", // prefix+name+suffix
+ "%.0s%s%.0s", // name
+ "%.0s%s%s", // name+suffix
+ "%s%s%.0s", // prefix+name
+ };
+ const int skipPrefixing = strchr(shortAsciiName, '/') != NULL; // skip prefixing if the name is actually a path
+ for (int i = 0; i < 4; i++)
+ {
+ if (skipPrefixing && (i == 0 || i == 3)) // 0th and 3rd strings include prefixes
+ continue;
+
+ _ASSERTE(dl_handle == nullptr);
+ if (snprintf(fullLibraryName, MAX_LONGPATH, formatStrings[i], PAL_SHLIB_PREFIX, shortAsciiName, PAL_SHLIB_SUFFIX) < MAX_LONGPATH)
+ {
+ dl_handle = LOADLoadLibraryDirect(fullLibraryName, false /* setLastError */);
+ if (dl_handle != nullptr)
+ {
+ shortAsciiName = fullLibraryName;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!dl_handle)
+ {
+ WARN("dlopen() failed; dlerror says '%s'\n", dlerror());
+ SetLastError(ERROR_MOD_NOT_FOUND);
+ goto done;
+ }
+
+ module = LOADRegisterLibraryDirect(dl_handle, shortAsciiName, fDynamic);
+
done:
UnlockModuleList();
- return (HMODULE)module;
+ return module;
}
/*++