1 //===- llvm/unittest/Support/DynamicLibrary/DynamicLibraryTest.cpp --------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Support/DynamicLibrary.h" 10 #include "llvm/Config/config.h" 11 #include "llvm/Support/FileSystem.h" 12 #include "llvm/Support/ManagedStatic.h" 13 #include "llvm/Support/Path.h" 14 #include "gtest/gtest.h" 15 16 #include "PipSqueak.h" 17 18 using namespace llvm; 19 using namespace llvm::sys; 20 21 std::string LibPath(const std::string Name = "PipSqueak") { 22 const std::vector<testing::internal::string> &Argvs = 23 testing::internal::GetArgvs(); 24 const char *Argv0 = 25 Argvs.size() > 0 ? Argvs[0].c_str() : "DynamicLibraryTests"; 26 void *Ptr = (void*)(intptr_t)TestA; 27 std::string Path = fs::getMainExecutable(Argv0, Ptr); 28 llvm::SmallString<256> Buf(path::parent_path(Path)); 29 path::append(Buf, (Name + LTDL_SHLIB_EXT).c_str()); 30 return Buf.str(); 31 } 32 33 #if defined(_WIN32) || (defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN)) 34 35 typedef void (*SetStrings)(std::string &GStr, std::string &LStr); 36 typedef void (*TestOrder)(std::vector<std::string> &V); 37 typedef const char *(*GetString)(); 38 39 template <class T> static T FuncPtr(void *Ptr) { 40 union { 41 T F; 42 void *P; 43 } Tmp; 44 Tmp.P = Ptr; 45 return Tmp.F; 46 } 47 template <class T> static void* PtrFunc(T *Func) { 48 union { 49 T *F; 50 void *P; 51 } Tmp; 52 Tmp.F = Func; 53 return Tmp.P; 54 } 55 56 static const char *OverloadTestA() { return "OverloadCall"; } 57 58 std::string StdString(const char *Ptr) { return Ptr ? Ptr : ""; } 59 60 TEST(DynamicLibrary, Overload) { 61 { 62 std::string Err; 63 llvm_shutdown_obj Shutdown; 64 DynamicLibrary DL = 65 DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err); 66 EXPECT_TRUE(DL.isValid()); 67 EXPECT_TRUE(Err.empty()); 68 69 GetString GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA")); 70 EXPECT_TRUE(GS != nullptr && GS != &TestA); 71 EXPECT_EQ(StdString(GS()), "LibCall"); 72 73 GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); 74 EXPECT_TRUE(GS != nullptr && GS != &TestA); 75 EXPECT_EQ(StdString(GS()), "LibCall"); 76 77 DL = DynamicLibrary::getPermanentLibrary(nullptr, &Err); 78 EXPECT_TRUE(DL.isValid()); 79 EXPECT_TRUE(Err.empty()); 80 81 // Test overloading local symbols does not occur by default 82 GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); 83 EXPECT_TRUE(GS != nullptr && GS == &TestA); 84 EXPECT_EQ(StdString(GS()), "ProcessCall"); 85 86 GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA")); 87 EXPECT_TRUE(GS != nullptr && GS == &TestA); 88 EXPECT_EQ(StdString(GS()), "ProcessCall"); 89 90 // Test overloading by forcing library priority when searching for a symbol 91 DynamicLibrary::SearchOrder = DynamicLibrary::SO_LoadedFirst; 92 GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); 93 EXPECT_TRUE(GS != nullptr && GS != &TestA); 94 EXPECT_EQ(StdString(GS()), "LibCall"); 95 96 DynamicLibrary::AddSymbol("TestA", PtrFunc(&OverloadTestA)); 97 GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA")); 98 EXPECT_TRUE(GS != nullptr && GS != &OverloadTestA); 99 100 GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); 101 EXPECT_TRUE(GS != nullptr && GS == &OverloadTestA); 102 EXPECT_EQ(StdString(GS()), "OverloadCall"); 103 } 104 EXPECT_TRUE(FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol( 105 "TestA")) == nullptr); 106 107 // Check serach ordering is reset to default after call to llvm_shutdown 108 EXPECT_TRUE(DynamicLibrary::SearchOrder == DynamicLibrary::SO_Linker); 109 } 110 111 TEST(DynamicLibrary, Shutdown) { 112 std::string A("PipSqueak"), B, C("SecondLib"); 113 std::vector<std::string> Order; 114 { 115 std::string Err; 116 llvm_shutdown_obj Shutdown; 117 DynamicLibrary DL = 118 DynamicLibrary::getPermanentLibrary(LibPath(A).c_str(), &Err); 119 EXPECT_TRUE(DL.isValid()); 120 EXPECT_TRUE(Err.empty()); 121 122 SetStrings SS_0 = FuncPtr<SetStrings>( 123 DynamicLibrary::SearchForAddressOfSymbol("SetStrings")); 124 EXPECT_TRUE(SS_0 != nullptr); 125 126 SS_0(A, B); 127 EXPECT_EQ(B, "Local::Local(PipSqueak)"); 128 129 TestOrder TO_0 = FuncPtr<TestOrder>( 130 DynamicLibrary::SearchForAddressOfSymbol("TestOrder")); 131 EXPECT_TRUE(TO_0 != nullptr); 132 133 DynamicLibrary DL2 = 134 DynamicLibrary::getPermanentLibrary(LibPath(C).c_str(), &Err); 135 EXPECT_TRUE(DL2.isValid()); 136 EXPECT_TRUE(Err.empty()); 137 138 // Should find latest version of symbols in SecondLib 139 SetStrings SS_1 = FuncPtr<SetStrings>( 140 DynamicLibrary::SearchForAddressOfSymbol("SetStrings")); 141 EXPECT_TRUE(SS_1 != nullptr); 142 EXPECT_TRUE(SS_0 != SS_1); 143 144 TestOrder TO_1 = FuncPtr<TestOrder>( 145 DynamicLibrary::SearchForAddressOfSymbol("TestOrder")); 146 EXPECT_TRUE(TO_1 != nullptr); 147 EXPECT_TRUE(TO_0 != TO_1); 148 149 B.clear(); 150 SS_1(C, B); 151 EXPECT_EQ(B, "Local::Local(SecondLib)"); 152 153 TO_0(Order); 154 TO_1(Order); 155 } 156 EXPECT_EQ(A, "Global::~Global"); 157 EXPECT_EQ(B, "Local::~Local"); 158 EXPECT_TRUE(FuncPtr<SetStrings>(DynamicLibrary::SearchForAddressOfSymbol( 159 "SetStrings")) == nullptr); 160 161 // Test unload/destruction ordering 162 EXPECT_EQ(Order.size(), 2UL); 163 EXPECT_EQ(Order.front(), "SecondLib"); 164 EXPECT_EQ(Order.back(), "PipSqueak"); 165 } 166 167 #else 168 169 TEST(DynamicLibrary, Unsupported) { 170 std::string Err; 171 DynamicLibrary DL = 172 DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err); 173 EXPECT_FALSE(DL.isValid()); 174 EXPECT_EQ(Err, "dlopen() not supported on this platform"); 175 } 176 177 #endif 178