xref: /llvm-project/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp (revision 6391c7e2a13ad00af853d0eeff718ddde8807da6)
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 "gtest/gtest.h"
16 
17 #include "PipSqueak.h"
18 
19 using namespace llvm;
20 using namespace llvm::sys;
21 
22 std::string LibPath(const std::string Name = "PipSqueak") {
23   const std::vector<testing::internal::string>& Argvs = testing::internal::GetArgvs();
24   const char *Argv0 = 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+".so").c_str());
29   return 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_TRUE(GS != nullptr && GS != &TestA);
70     EXPECT_EQ(StdString(GS()), "LibCall");
71 
72     GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
73     EXPECT_TRUE(GS != nullptr && GS != &TestA);
74     EXPECT_EQ(StdString(GS()), "LibCall");
75 
76     DL = DynamicLibrary::getPermanentLibrary(nullptr, &Err);
77     EXPECT_TRUE(DL.isValid());
78     EXPECT_TRUE(Err.empty());
79 
80     GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
81     EXPECT_TRUE(GS != nullptr && GS == &TestA);
82     EXPECT_EQ(StdString(GS()), "ProcessCall");
83 
84     GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA"));
85     EXPECT_TRUE(GS != nullptr && GS == &TestA);
86     EXPECT_EQ(StdString(GS()), "ProcessCall");
87 
88     DynamicLibrary::AddSymbol("TestA", PtrFunc(&OverloadTestA));
89     GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA"));
90     EXPECT_TRUE(GS != nullptr && GS != &OverloadTestA);
91 
92     GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
93     EXPECT_TRUE(GS != nullptr && GS == &OverloadTestA);
94     EXPECT_EQ(StdString(GS()), "OverloadCall");
95   }
96   EXPECT_TRUE(FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol(
97                   "TestA")) == nullptr);
98 }
99 
100 TEST(DynamicLibrary, Shutdown) {
101   std::string A("PipSqueak"), B, C("SecondLib");
102   std::vector<std::string> Order;
103   {
104     std::string Err;
105     llvm_shutdown_obj Shutdown;
106     DynamicLibrary DL =
107         DynamicLibrary::getPermanentLibrary(LibPath(A).c_str(), &Err);
108     EXPECT_TRUE(DL.isValid());
109     EXPECT_TRUE(Err.empty());
110 
111     SetStrings SS_0 = FuncPtr<SetStrings>(
112         DynamicLibrary::SearchForAddressOfSymbol("SetStrings"));
113     EXPECT_TRUE(SS_0 != nullptr);
114 
115     SS_0(A, B);
116     EXPECT_EQ(B, "Local::Local(PipSqueak)");
117 
118     TestOrder TO_0 = FuncPtr<TestOrder>(
119         DynamicLibrary::SearchForAddressOfSymbol("TestOrder"));
120     EXPECT_TRUE(TO_0 != nullptr);
121 
122     DynamicLibrary DL2 =
123         DynamicLibrary::getPermanentLibrary(LibPath(C).c_str(), &Err);
124     EXPECT_TRUE(DL2.isValid());
125     EXPECT_TRUE(Err.empty());
126 
127     // Should find latest version of symbols in SecondLib
128     SetStrings SS_1 = FuncPtr<SetStrings>(
129         DynamicLibrary::SearchForAddressOfSymbol("SetStrings"));
130     EXPECT_TRUE(SS_1 != nullptr);
131     EXPECT_TRUE(SS_0 != SS_1);
132 
133     TestOrder TO_1 = FuncPtr<TestOrder>(
134         DynamicLibrary::SearchForAddressOfSymbol("TestOrder"));
135     EXPECT_TRUE(TO_1 != nullptr);
136     EXPECT_TRUE(TO_0 != TO_1);
137 
138     B.clear();
139     SS_1(C, B);
140     EXPECT_EQ(B, "Local::Local(SecondLib)");
141 
142     TO_0(Order);
143     TO_1(Order);
144   }
145   EXPECT_EQ(A, "Global::~Global");
146   EXPECT_EQ(B, "Local::~Local");
147   EXPECT_TRUE(FuncPtr<SetStrings>(DynamicLibrary::SearchForAddressOfSymbol(
148                   "SetStrings")) == nullptr);
149 
150   // Test unload/destruction ordering
151   EXPECT_EQ(Order.size(), 2UL);
152   EXPECT_EQ(Order.front(), "SecondLib");
153   EXPECT_EQ(Order.back(), "PipSqueak");
154 }
155 
156 #else
157 
158 TEST(DynamicLibrary, Unsupported) {
159   std::string Err;
160   DynamicLibrary DL =
161       DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
162   EXPECT_FALSE(DL.isValid());
163   EXPECT_EQ(Err, "dlopen() not supported on this platform");
164 }
165 
166 #endif
167