Index: include/llvm/Support/DynamicLibrary.h =================================================================== --- include/llvm/Support/DynamicLibrary.h +++ include/llvm/Support/DynamicLibrary.h @@ -44,24 +44,43 @@ void *Data; public: - explicit DynamicLibrary(void *data = &Invalid) : Data(data) {} + explicit DynamicLibrary(void *Handle = &Invalid) : Data(Handle) {} + + /// @brief Load the library from Filename storing errors in ErrMsg. + DynamicLibrary(const char *Filename, std::string *ErrMsg = nullptr, + bool RTLocal = false); + + /// @brief Convenience function for using RTLocal without error reporting. + DynamicLibrary(const char *Filename, bool RTLocal) + : DynamicLibrary(Filename, nullptr, RTLocal) {} + + DynamicLibrary(DynamicLibrary &&Other) : Data(Other.Data) { + Other.Data = &Invalid; + } + + DynamicLibrary(const DynamicLibrary&) = delete; + ~DynamicLibrary(); /// Returns true if the object refers to a valid library. bool isValid() const { return Data != &Invalid; } + /// Comparison operators + operator bool () const { return isValid(); } + bool operator == (const void *Handle) { return Data == Handle; } + bool operator != (const void *Handle) { return Data != Handle; } + bool operator < (const void *Handle) { return Data < Handle; } + /// Searches through the library for the symbol \p symbolName. If it is /// found, the address of that symbol is returned. If not, NULL is returned. - /// Note that NULL will also be returned if the library failed to load. - /// Use isValid() to distinguish these cases if it is important. /// Note that this will \e not search symbols explicitly registered by /// AddSymbol(). - void *getAddressOfSymbol(const char *symbolName); + void *getAddressOfSymbol(const char *SymbolName); /// This function permanently loads the dynamic library at the given path. /// The library will only be unloaded when llvm_shutdown() is called. - /// This returns a valid DynamicLibrary instance on success and an invalid - /// instance on failure (see isValid()). \p *errMsg will only be modified - /// if the library fails to load. + /// This returns a pointer to the DynamicLibrary instance on success and an + /// nullptr on failure . \p *errMsg will only be modified if the library + /// fails to load. /// /// It is safe to call this function multiple times for the same library. /// @brief Open a dynamic library permanently. @@ -69,13 +88,13 @@ /// @param ErrMsg Any error encountered will be stored here. /// @param RTLocal Open with RTLD_LOCAL flag on platforms supporting dlopen, /// otherwise ignored. - static DynamicLibrary getPermanentLibrary(const char *Filename, - std::string *ErrMsg = nullptr, - bool RTLocal = false); + static DynamicLibrary *getPermanentLibrary(const char *Filename, + std::string *ErrMsg = nullptr, + bool RTLocal = false); /// @brief Convenience function for using RTLocal without error reporting. - static DynamicLibrary getPermanentLibrary(const char *Filename, - bool RTLocal) { + static DynamicLibrary *getPermanentLibrary(const char *Filename, + bool RTLocal) { return getPermanentLibrary(Filename, nullptr, RTLocal); } @@ -86,17 +105,19 @@ /// though ownership is only taken if there was no error. /// /// \returns An empty \p DynamicLibrary if the library was already loaded. - static DynamicLibrary addPermanentLibrary(void *handle, - std::string *errMsg = nullptr); + static DynamicLibrary *addPermanentLibrary(void *Handle, + std::string *ErrMsg = nullptr); /// This function permanently loads the dynamic library at the given path. /// Use this instead of getPermanentLibrary() when you won't need to get /// symbols from the library itself. /// /// It is safe to call this function multiple times for the same library. + /// + /// \returns 0 if successful, 1 otherwise. static bool LoadLibraryPermanently(const char *Filename, std::string *ErrMsg = nullptr) { - return !getPermanentLibrary(Filename, ErrMsg).isValid(); + return getPermanentLibrary(Filename, ErrMsg) == nullptr; } enum SearchOrdering { Index: lib/Support/DynamicLibrary.cpp =================================================================== --- lib/Support/DynamicLibrary.cpp +++ lib/Support/DynamicLibrary.cpp @@ -28,16 +28,17 @@ // All methods for HandleSet should be used holding SymbolsMutex. class DynamicLibrary::HandleSet { - typedef std::vector HandleList; + typedef std::vector HandleList; + typedef std::pair ReturnTy; HandleList Handles; - void *Process; + DynamicLibrary Process; public: static void *DLOpen(const char *Filename, std::string *Err, bool Local); static void DLClose(void *Handle); static void *DLSym(void *Handle, const char *Symbol); - HandleSet() : Process(nullptr) {} + HandleSet() {} ~HandleSet(); HandleList::iterator Find(void *Handle) { @@ -45,44 +46,44 @@ } bool Contains(void *Handle) { - return Handle == Process || Find(Handle) != Handles.end(); + return Handle == Process.Data || Find(Handle) != Handles.end(); } - bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) { + ReturnTy AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = 1) { + assert(Handle != &DynamicLibrary::Invalid); #ifdef LLVM_ON_WIN32 assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle."); #endif if (LLVM_LIKELY(!IsProcess)) { - if (Find(Handle) != Handles.end()) { + auto Itr = Find(Handle); + if (Itr != Handles.end()) { if (CanClose) DLClose(Handle); - return false; + return ReturnTy(&(*Itr), false); } - Handles.push_back(Handle); - } else { -#ifndef LLVM_ON_WIN32 - if (Process) { - if (CanClose) - DLClose(Process); - if (Process == Handle) - return false; - } -#endif - Process = Handle; + Handles.emplace_back(Handle); + return ReturnTy(&Handles.back(), true); } - return true; + + bool FirstTime = (Process.Data == &DynamicLibrary::Invalid); + if (!FirstTime) { + if (CanClose) + DLClose(Process.Data); + } + Process.Data = Handle; + return ReturnTy(&Process, FirstTime); } void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { if (Order & SO_LoadOrder) { - for (void *Handle : Handles) { - if (void *Ptr = DLSym(Handle, Symbol)) + for (DynamicLibrary &DL : Handles) { + if (void *Ptr = DLSym(DL.Data, Symbol)) return Ptr; } } else { - for (void *Handle : llvm::reverse(Handles)) { - if (void *Ptr = DLSym(Handle, Symbol)) + for (DynamicLibrary &DL : llvm::reverse(Handles)) { + if (void *Ptr = DLSym(DL.Data, Symbol)) return Ptr; } } @@ -99,7 +100,7 @@ } if (Process) { // Use OS facilities to search the current binary and all loaded libs. - if (void *Ptr = DLSym(Process, Symbol)) + if (void *Ptr = DLSym(Process.Data, Symbol)) return Ptr; // Search any libs that might have been skipped because of RTLD_LOCAL. @@ -141,34 +142,43 @@ } } +DynamicLibrary::DynamicLibrary(const char *File, std::string *Err, bool RTLocal) + : Data(HandleSet::DLOpen(File, Err, RTLocal)) {} + +DynamicLibrary::~DynamicLibrary() { + if (isValid()) + HandleSet::DLClose(Data); +} + void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) { SmartScopedLock Lock(*SymbolsMutex); (*ExplicitSymbols)[SymbolName] = SymbolValue; } -DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName, - std::string *Err, bool Lcl) { +DynamicLibrary *DynamicLibrary::getPermanentLibrary(const char *FileName, + std::string *Err, bool LC) { // Force OpenedHandles to be added into the ManagedStatic list before any // ManagedStatic can be added from static constructors in HandleSet::DLOpen. HandleSet& HS = *OpenedHandles; - void *Handle = HandleSet::DLOpen(FileName, Err, Lcl); + void *Handle = HandleSet::DLOpen(FileName, Err, LC); if (Handle != &Invalid) { SmartScopedLock Lock(*SymbolsMutex); - HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr); + return HS.AddLibrary(Handle, /*IsProcess*/FileName == nullptr).first; } - return DynamicLibrary(Handle); + return nullptr; } -DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle, - std::string *Err) { +DynamicLibrary *DynamicLibrary::addPermanentLibrary(void *Handle, + std::string *Err) { SmartScopedLock Lock(*SymbolsMutex); + auto DL = OpenedHandles->AddLibrary(Handle, false, /*CanClose*/false); // If we've already loaded this library, tell the caller. - if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false)) + if (!DL.second) *Err = "Library already loaded"; - return DynamicLibrary(Handle); + return DL.first; } void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) { Index: lib/Support/Unix/DynamicLibrary.inc =================================================================== --- lib/Support/Unix/DynamicLibrary.inc +++ lib/Support/Unix/DynamicLibrary.inc @@ -16,10 +16,15 @@ DynamicLibrary::HandleSet::~HandleSet() { // Close the libraries in reverse order. - for (void *Handle : llvm::reverse(Handles)) - ::dlclose(Handle); - if (Process) - ::dlclose(Process); + for (DynamicLibrary &DL : llvm::reverse(Handles)) { + assert(DL.Data != &DynamicLibrary::Invalid); + ::dlclose(DL.Data); + DL.Data = &DynamicLibrary::Invalid; + } + if (Process) { + ::dlclose(Process.Data); + Process.Data = &DynamicLibrary::Invalid; + } // llvm_shutdown called, Return to default DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; Index: lib/Support/Windows/DynamicLibrary.inc =================================================================== --- lib/Support/Windows/DynamicLibrary.inc +++ lib/Support/Windows/DynamicLibrary.inc @@ -23,11 +23,14 @@ DynamicLibrary::HandleSet::~HandleSet() { - for (void *Handle : llvm::reverse(Handles)) - FreeLibrary(HMODULE(Handle)); + for (DynamicLibrary &DL : llvm::reverse(Handles)) { + assert(DL.Data != &DynamicLibrary::Invalid); + FreeLibrary(HMODULE(DL.Data)); + DL.Data = &DynamicLibrary::Invalid; + } + if (Process) + Process.Data = &DynamicLibrary::Invalid; - // 'Process' should not be released on Windows. - assert((!Process || Process==this) && "Bad Handle"); // llvm_shutdown called, Return to default DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; } @@ -64,7 +67,7 @@ void DynamicLibrary::HandleSet::DLClose(void *Handle) { if (HandleSet* HS = IsOpenedHandlesInstance(Handle)) - HS->Process = nullptr; // Just drop the *Process* handle. + HS->Process.Data = &DynamicLibrary::Invalid; // Invalidate the fake handle. else FreeLibrary((HMODULE)Handle); } Index: unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp =================================================================== --- unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp +++ unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp @@ -60,12 +60,12 @@ { std::string Err; llvm_shutdown_obj Shutdown; - DynamicLibrary DL = + DynamicLibrary *DL = DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err, RTLocal); - EXPECT_TRUE(DL.isValid()); + EXPECT_TRUE(DL != nullptr); EXPECT_TRUE(Err.empty()); - GetString GS = FuncPtr(DL.getAddressOfSymbol("TestA")); + GetString GS = FuncPtr(DL->getAddressOfSymbol("TestA")); EXPECT_TRUE(GS != nullptr && GS != &TestA); EXPECT_EQ(StdString(GS()), "LibCall"); @@ -74,7 +74,7 @@ EXPECT_EQ(StdString(GS()), "LibCall"); DL = DynamicLibrary::getPermanentLibrary(nullptr, &Err); - EXPECT_TRUE(DL.isValid()); + EXPECT_TRUE(DL != nullptr); EXPECT_TRUE(Err.empty()); // Test overloading local symbols does not occur by default @@ -82,7 +82,7 @@ EXPECT_TRUE(GS != nullptr && GS == &TestA); EXPECT_EQ(StdString(GS()), "ProcessCall"); - GS = FuncPtr(DL.getAddressOfSymbol("TestA")); + GS = FuncPtr(DL->getAddressOfSymbol("TestA")); EXPECT_TRUE(GS != nullptr && GS == &TestA); EXPECT_EQ(StdString(GS()), "ProcessCall"); @@ -119,7 +119,7 @@ } DynamicLibrary::AddSymbol("TestA", PtrFunc(&OverloadTestA)); - GS = FuncPtr(DL.getAddressOfSymbol("TestA")); + GS = FuncPtr(DL->getAddressOfSymbol("TestA")); EXPECT_TRUE(GS != nullptr && GS != &OverloadTestA); GS = FuncPtr(DynamicLibrary::SearchForAddressOfSymbol("TestA")); @@ -149,9 +149,9 @@ { std::string Err; llvm_shutdown_obj Shutdown; - DynamicLibrary DL = + DynamicLibrary *DL = DynamicLibrary::getPermanentLibrary(LibPath(A).c_str(), &Err); - EXPECT_TRUE(DL.isValid()); + EXPECT_TRUE(DL != nullptr); EXPECT_TRUE(Err.empty()); SetStrings SS_0 = FuncPtr( @@ -165,9 +165,9 @@ DynamicLibrary::SearchForAddressOfSymbol("TestOrder")); EXPECT_TRUE(TO_0 != nullptr); - DynamicLibrary DL2 = + DynamicLibrary *DL2 = DynamicLibrary::getPermanentLibrary(LibPath(C).c_str(), &Err); - EXPECT_TRUE(DL2.isValid()); + EXPECT_TRUE(DL2 != nullptr); EXPECT_TRUE(Err.empty()); // Should find latest version of symbols in SecondLib @@ -199,6 +199,24 @@ EXPECT_EQ(Order.back(), "PipSqueak"); } +TEST(DynamicLibrary, Scope) { + std::string A, B; + { + std::string Err; + DynamicLibrary DL(LibPath().c_str(), &Err); + EXPECT_TRUE(DL.isValid()); + EXPECT_TRUE(Err.empty()); + + SetStrings SS = FuncPtr(DL.getAddressOfSymbol("SetStrings")); + EXPECT_TRUE(SS != nullptr); + + SS(A, B); + EXPECT_EQ(B, "Local::Local"); + } + EXPECT_EQ(A, "Global::~Global"); + EXPECT_EQ(B, "Local::~Local"); +} + #else TEST(DynamicLibrary, Unsupported) {