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