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