xref: /llvm-project/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp (revision 4c73b40dca42c802babc565430bd50c7edb48cef)
1 //===- llvm/unittest/Support/DynamicLibrary/DynamicLibraryTest.cpp --------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/Support/DynamicLibrary.h"
11 #include "llvm/Config/config.h"
12 #include "llvm/Support/FileSystem.h"
13 #include "llvm/Support/ManagedStatic.h"
14 #include "llvm/Support/Path.h"
15 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
16 #include "gtest/gtest.h"
17 
18 #include "PipSqueak.h"
19 
20 using namespace llvm;
21 using namespace llvm::sys;
22 
23 std::string LibPath(const std::string Name = "PipSqueak") {
24   const std::vector<testing::internal::string>& Argvs = testing::internal::GetArgvs();
25   const char *Argv0 = 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+".so").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 void
57 NoPassRegistration(const PassManagerBuilder &, legacy::PassManagerBase &) {
58 }
59 
60 static RegisterStandardPasses LocalPass(PassManagerBuilder::EP_LoopOptimizerEnd,
61                                         NoPassRegistration);
62 
63 typedef void (*TestPassReg)(void (*)(PassManagerBuilder::ExtensionPointTy,
64                                      PassManagerBuilder::ExtensionProc));
65 
66 TEST(DynamicLibrary, PassRegistration) {
67   std::string Err;
68   llvm_shutdown_obj Shutdown;
69   DynamicLibrary DL =
70       DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
71   EXPECT_TRUE(DL.isValid());
72   EXPECT_TRUE(Err.empty());
73 
74   TestPassReg RP = FuncPtr<TestPassReg>(DL.getAddressOfSymbol("TestPassReg"));
75   RP(&PassManagerBuilder::addGlobalExtension);
76 }
77 
78 static const char *OverloadTestA() { return "OverloadCall"; }
79 
80 std::string StdString(const char *Ptr) { return Ptr ? Ptr : ""; }
81 
82 TEST(DynamicLibrary, Overload) {
83   {
84     std::string Err;
85     llvm_shutdown_obj Shutdown;
86     DynamicLibrary DL =
87         DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
88     EXPECT_TRUE(DL.isValid());
89     EXPECT_TRUE(Err.empty());
90 
91     GetString GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA"));
92     EXPECT_TRUE(GS != nullptr && GS != &TestA);
93     EXPECT_EQ(StdString(GS()), "LibCall");
94 
95     GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
96     EXPECT_TRUE(GS != nullptr && GS != &TestA);
97     EXPECT_EQ(StdString(GS()), "LibCall");
98 
99     DL = DynamicLibrary::getPermanentLibrary(nullptr, &Err);
100     EXPECT_TRUE(DL.isValid());
101     EXPECT_TRUE(Err.empty());
102 
103     GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
104     EXPECT_TRUE(GS != nullptr && GS == &TestA);
105     EXPECT_EQ(StdString(GS()), "ProcessCall");
106 
107     GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA"));
108     EXPECT_TRUE(GS != nullptr && GS == &TestA);
109     EXPECT_EQ(StdString(GS()), "ProcessCall");
110 
111     DynamicLibrary::AddSymbol("TestA", PtrFunc(&OverloadTestA));
112     GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA"));
113     EXPECT_TRUE(GS != nullptr && GS != &OverloadTestA);
114 
115     GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
116     EXPECT_TRUE(GS != nullptr && GS == &OverloadTestA);
117     EXPECT_EQ(StdString(GS()), "OverloadCall");
118   }
119   EXPECT_TRUE(FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol(
120                   "TestA")) == nullptr);
121 }
122 
123 TEST(DynamicLibrary, Shutdown) {
124   std::string A("PipSqueak"), B, C("SecondLib");
125   std::vector<std::string> Order;
126   {
127     std::string Err;
128     llvm_shutdown_obj Shutdown;
129     DynamicLibrary DL =
130         DynamicLibrary::getPermanentLibrary(LibPath(A).c_str(), &Err);
131     EXPECT_TRUE(DL.isValid());
132     EXPECT_TRUE(Err.empty());
133 
134     SetStrings SS_0 = FuncPtr<SetStrings>(
135         DynamicLibrary::SearchForAddressOfSymbol("SetStrings"));
136     EXPECT_TRUE(SS_0 != nullptr);
137 
138     SS_0(A, B);
139     EXPECT_EQ(B, "Local::Local(PipSqueak)");
140 
141     TestOrder TO_0 = FuncPtr<TestOrder>(
142         DynamicLibrary::SearchForAddressOfSymbol("TestOrder"));
143     EXPECT_TRUE(TO_0 != nullptr);
144 
145     DynamicLibrary DL2 =
146         DynamicLibrary::getPermanentLibrary(LibPath(C).c_str(), &Err);
147     EXPECT_TRUE(DL2.isValid());
148     EXPECT_TRUE(Err.empty());
149 
150     // Should find latest version of symbols in SecondLib
151     SetStrings SS_1 = FuncPtr<SetStrings>(
152         DynamicLibrary::SearchForAddressOfSymbol("SetStrings"));
153     EXPECT_TRUE(SS_1 != nullptr);
154     EXPECT_TRUE(SS_0 != SS_1);
155 
156     TestOrder TO_1 = FuncPtr<TestOrder>(
157         DynamicLibrary::SearchForAddressOfSymbol("TestOrder"));
158     EXPECT_TRUE(TO_1 != nullptr);
159     EXPECT_TRUE(TO_0 != TO_1);
160 
161     B.clear();
162     SS_1(C, B);
163     EXPECT_EQ(B, "Local::Local(SecondLib)");
164 
165     TO_0(Order);
166     TO_1(Order);
167   }
168   EXPECT_EQ(A, "Global::~Global");
169   EXPECT_EQ(B, "Local::~Local");
170   EXPECT_TRUE(FuncPtr<SetStrings>(DynamicLibrary::SearchForAddressOfSymbol(
171                   "SetStrings")) == nullptr);
172 
173   // Test unload/destruction ordering
174   EXPECT_EQ(Order.size(), 2UL);
175   EXPECT_EQ(Order.front(), "SecondLib");
176   EXPECT_EQ(Order.back(), "PipSqueak");
177 }
178 
179 #else
180 
181 TEST(DynamicLibrary, Unsupported) {
182   std::string Err;
183   DynamicLibrary DL =
184       DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
185   EXPECT_FALSE(DL.isValid());
186   EXPECT_EQ(Err, "dlopen() not supported on this platform");
187 }
188 
189 #endif
190