Index: lib/Support/DynamicLibrary.cpp =================================================================== --- lib/Support/DynamicLibrary.cpp +++ lib/Support/DynamicLibrary.cpp @@ -49,7 +49,43 @@ //=== independent code. //===----------------------------------------------------------------------===// -static llvm::ManagedStatic > OpenedHandles; +namespace { + +class HandleSet { + // Cannot use an llvm::SetVector as no access to internal vector there. + std::vector Handles; + bool KeepFront; +public: + HandleSet() : KeepFront(false) {} + + void AddLibrary(void* Handle, bool IsProcess = false, bool CanClose = true) { + // Check if we've already loaded this library. + if (std::find(Handles.begin(), Handles.end(), Handle) != Handles.end()) { + // dlclose() the handle in order to keep the internal refcount at +1. + if (CanClose) + dlclose(Handle); + return; + } + + Handles.push_back(Handle); + + // Keep current process handle at top of list + if (!IsProcess && KeepFront) { + const size_t Len = Handles.size(); + if (Len > 2) + std::swap(Handles[Len-1], Handles[Len-2]); + } else if (IsProcess) + KeepFront = true; + } + + // Iterate in reverse, so newer libraries/symbols override older. + std::vector::reverse_iterator begin() { return Handles.rbegin(); } + std::vector::reverse_iterator end() { return Handles.rend(); } +}; + +static llvm::ManagedStatic OpenedHandles; + +} DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, std::string *errMsg) { @@ -68,10 +104,7 @@ handle = RTLD_DEFAULT; #endif - // If we've already loaded this library, dlclose() the handle in order to - // keep the internal refcount at +1. - if (!OpenedHandles->insert(handle).second) - dlclose(handle); + OpenedHandles->AddLibrary(handle, filename==nullptr); return DynamicLibrary(handle); } @@ -117,10 +150,8 @@ #if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN) // Now search the libraries. if (OpenedHandles.isConstructed()) { - for (DenseSet::iterator I = OpenedHandles->begin(), - E = OpenedHandles->end(); I != E; ++I) { - //lt_ptr ptr = lt_dlsym(*I, symbolName); - void *ptr = dlsym(*I, symbolName); + for (void *Handle : *OpenedHandles) { + void *ptr = dlsym(Handle, symbolName); if (ptr) { return ptr; } Index: lib/Support/Windows/DynamicLibrary.inc =================================================================== --- lib/Support/Windows/DynamicLibrary.inc +++ lib/Support/Windows/DynamicLibrary.inc @@ -9,8 +9,6 @@ // // This file provides the Win32 specific implementation of DynamicLibrary. // -// FIXME: This file leaks OpenedHandles! -// //===----------------------------------------------------------------------===// #include "WindowsSupport.h" @@ -18,12 +16,13 @@ #ifdef __MINGW32__ #include #else - #include + #include #endif #ifdef _MSC_VER #include #endif +#include namespace llvm { using namespace sys; @@ -33,24 +32,80 @@ //=== and must not be UNIX code. //===----------------------------------------------------------------------===// -typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); -static fpEnumerateLoadedModules fEnumerateLoadedModules; -static DenseSet *OpenedHandles; +namespace { + +class ModuleHandles { + typedef std::vector ModuleList; + + ModuleList Modules; + bool KeepFront; + +public: + ModuleHandles() : KeepFront(false) {} + + ModuleHandles* GetProcessModules(std::string *errMsg) { +#ifdef _WIN64 + const DWORD Flags = LIST_MODULES_64BIT; +#else + const DWORD Flags = LIST_MODULES_32BIT; +#endif -static bool loadDebugHelp(void) { - HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); - if (hLib) { - fEnumerateLoadedModules = (fpEnumerateLoadedModules) - ::GetProcAddress(hLib, "EnumerateLoadedModules64"); + DWORD Bytes; + HMODULE Self = (HMODULE)GetCurrentProcess(); + if (!EnumProcessModulesEx(Self, nullptr, 0, &Bytes, Flags)) { + MakeErrMsg(errMsg, "EnumProcessModulesEx failure"); + return nullptr; + } + + // Get the most recent list in case any modules added between calls to + // EnumProcessModulesEx to get size and second call to copy libs. + do { + assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) && + "Should have at least one module and be aligned"); + Modules.resize(Bytes / sizeof(HMODULE)); + if (!EnumProcessModulesEx(Self, Modules.data(), Bytes, &Bytes, Flags)) { + MakeErrMsg(errMsg, "EnumProcessModulesEx failure"); + return nullptr; + } + } while (Bytes != (Modules.size() * sizeof(HMODULE))); + + // Keep current process handle at top of list + KeepFront = true; + if (Modules.size() > 1) { + Self = Modules.front(); + memmove(Modules.data(), Modules.data()+1, Bytes - sizeof(HMODULE)); + Modules.back() = Self; + } + + return this; } - return fEnumerateLoadedModules != 0; -} -static BOOL CALLBACK -ELM_Callback(PCSTR ModuleName, DWORD64 ModuleBase, - ULONG ModuleSize, PVOID UserContext) { - OpenedHandles->insert((HMODULE)ModuleBase); - return TRUE; + void AddLibrary(HMODULE Lib, bool CanFree = true) { + // Check if we've already loaded this library. + if (std::find(Modules.begin(), Modules.end(), Lib) != Modules.end()) { + // FreeLibrary() the handle in order to keep the internal refcount at +1. + if (CanFree) + FreeLibrary(Lib); + return; + } + + Modules.push_back(Lib); + + // Keep current process handle at top of list. + if (KeepFront) { + const size_t Len = Modules.size(); + if (Len > 2) + std::swap(Modules[Len-1], Modules[Len-2]); + } + } + + // Iterate in reverse, so newer libraries/symbols override older. + ModuleList::reverse_iterator begin() { return Modules.rbegin(); } + ModuleList::reverse_iterator end() { return Modules.rend(); } +}; + +static llvm::ManagedStatic OpenedHandles; + } DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, @@ -59,20 +114,10 @@ if (!filename) { // When no file is specified, enumerate all DLLs and EXEs in the process. - if (OpenedHandles == 0) - OpenedHandles = new DenseSet(); - - if (!fEnumerateLoadedModules) { - if (!loadDebugHelp()) { - assert(false && "These APIs should always be available"); - return DynamicLibrary(); - } - } - fEnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0); // Dummy library that represents "search all handles". // This is mostly to ensure that the return value still shows up as "valid". - return DynamicLibrary(&OpenedHandles); + return DynamicLibrary(OpenedHandles->GetProcessModules(errMsg)); } SmallVector filenameUnicode; @@ -89,13 +134,7 @@ return DynamicLibrary(); } - if (OpenedHandles == 0) - OpenedHandles = new DenseSet(); - - // If we've already loaded this library, FreeLibrary() the handle in order to - // keep the internal refcount at +1. - if (!OpenedHandles->insert(a_handle).second) - FreeLibrary(a_handle); + OpenedHandles->AddLibrary(a_handle); return DynamicLibrary(a_handle); } @@ -136,11 +175,10 @@ return i->second; } - // Now search the libraries. - if (OpenedHandles) { - for (DenseSet::iterator I = OpenedHandles->begin(), - E = OpenedHandles->end(); I != E; ++I) { - FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName); + // Now search the libraries (in reverse, newer symbols override oldest) + if (OpenedHandles.isConstructed()) { + for (HMODULE Module : *OpenedHandles) { + FARPROC ptr = GetProcAddress(Module, symbolName); if (ptr) { return (void *)(intptr_t)ptr; } @@ -176,7 +214,7 @@ void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { if (!isValid()) return NULL; - if (Data == &OpenedHandles) + if (OpenedHandles.isConstructed() && Data == &(*OpenedHandles)) return SearchForAddressOfSymbol(symbolName); return (void *)(intptr_t)GetProcAddress((HMODULE)Data, symbolName); }