Skip to content

Commit ad12580

Browse files
author
Frederich Munch
committed
Close DynamicLibraries in reverse order they were opened.
Summary: Matches C++ destruction ordering better and fixes possible problems of loaded libraries having inter-dependencies. Reviewers: efriedma, v.g.vassilev, chapuni Reviewed By: efriedma Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D33652 llvm-svn: 304720
1 parent db3b87b commit ad12580

File tree

6 files changed

+91
-37
lines changed

6 files changed

+91
-37
lines changed

llvm/lib/Support/Unix/DynamicLibrary.inc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
#include <dlfcn.h>
1616

1717
DynamicLibrary::HandleSet::~HandleSet() {
18-
for (void *Handle : Handles)
18+
// Close the libraries in reverse order.
19+
for (void *Handle : llvm::reverse(Handles))
1920
::dlclose(Handle);
2021
if (Process)
2122
::dlclose(Process);

llvm/lib/Support/Windows/DynamicLibrary.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424

2525
DynamicLibrary::HandleSet::~HandleSet() {
26-
for (void *Handle : Handles)
26+
for (void *Handle : llvm::reverse(Handles))
2727
FreeLibrary(HMODULE(Handle));
2828

2929
// 'Process' should not be released on Windows.

llvm/unittests/Support/DynamicLibrary/CMakeLists.txt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,21 @@ add_llvm_unittest(DynamicLibraryTests DynamicLibraryTest.cpp)
44

55
export_executable_symbols(DynamicLibraryTests)
66

7-
add_library(PipSqueak SHARED PipSqueak.cxx)
7+
function(dynlib_add_module NAME)
8+
add_library(${NAME} SHARED PipSqueak.cxx)
89

9-
set_output_directory(PipSqueak
10-
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
11-
LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
12-
)
10+
set_output_directory(${NAME}
11+
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
12+
LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
13+
)
1314

14-
set_target_properties(PipSqueak
15-
PROPERTIES PREFIX ""
16-
SUFFIX ".so"
17-
)
15+
set_target_properties(${NAME}
16+
PROPERTIES PREFIX ""
17+
SUFFIX ".so"
18+
)
1819

19-
add_dependencies(DynamicLibraryTests PipSqueak)
20+
add_dependencies(DynamicLibraryTests ${NAME})
21+
endfunction(dynlib_add_module)
22+
23+
dynlib_add_module(PipSqueak)
24+
dynlib_add_module(SecondLib)

llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,26 @@
1515
#include "gtest/gtest.h"
1616

1717
#include "PipSqueak.h"
18-
#include <string>
1918

2019
using namespace llvm;
2120
using namespace llvm::sys;
2221

2322
extern "C" PIPSQUEAK_EXPORT const char *TestA() { return "ProcessCall"; }
2423

25-
std::string LibPath() {
24+
std::string LibPath(const std::string Name = "PipSqueak") {
2625
const std::vector<testing::internal::string>& Argvs = testing::internal::GetArgvs();
2726
const char *Argv0 = Argvs.size() > 0 ? Argvs[0].c_str() : "DynamicLibraryTests";
2827
void *Ptr = (void*)(intptr_t)TestA;
2928
std::string Path = fs::getMainExecutable(Argv0, Ptr);
3029
llvm::SmallString<256> Buf(path::parent_path(Path));
31-
path::append(Buf, "PipSqueak.so");
30+
path::append(Buf, (Name+".so").c_str());
3231
return Buf.str();
3332
}
3433

3534
#if defined(_WIN32) || (defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN))
3635

3736
typedef void (*SetStrings)(std::string &GStr, std::string &LStr);
37+
typedef void (*TestOrder)(std::vector<std::string> &V);
3838
typedef const char *(*GetString)();
3939

4040
template <class T> static T FuncPtr(void *Ptr) {
@@ -100,26 +100,59 @@ TEST(DynamicLibrary, Overload) {
100100
}
101101

102102
TEST(DynamicLibrary, Shutdown) {
103-
std::string A, B;
103+
std::string A("PipSqueak"), B, C("SecondLib");
104+
std::vector<std::string> Order;
104105
{
105106
std::string Err;
106107
llvm_shutdown_obj Shutdown;
107108
DynamicLibrary DL =
108-
DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
109+
DynamicLibrary::getPermanentLibrary(LibPath(A).c_str(), &Err);
109110
EXPECT_TRUE(DL.isValid());
110111
EXPECT_TRUE(Err.empty());
111112

112-
SetStrings SS = FuncPtr<SetStrings>(
113+
SetStrings SS_0 = FuncPtr<SetStrings>(
114+
DynamicLibrary::SearchForAddressOfSymbol("SetStrings"));
115+
EXPECT_TRUE(SS_0 != nullptr);
116+
117+
SS_0(A, B);
118+
EXPECT_EQ(B, "Local::Local(PipSqueak)");
119+
120+
TestOrder TO_0 = FuncPtr<TestOrder>(
121+
DynamicLibrary::SearchForAddressOfSymbol("TestOrder"));
122+
EXPECT_TRUE(TO_0 != nullptr);
123+
124+
DynamicLibrary DL2 =
125+
DynamicLibrary::getPermanentLibrary(LibPath(C).c_str(), &Err);
126+
EXPECT_TRUE(DL2.isValid());
127+
EXPECT_TRUE(Err.empty());
128+
129+
// Should find latest version of symbols in SecondLib
130+
SetStrings SS_1 = FuncPtr<SetStrings>(
113131
DynamicLibrary::SearchForAddressOfSymbol("SetStrings"));
114-
EXPECT_TRUE(SS != nullptr);
132+
EXPECT_TRUE(SS_1 != nullptr);
133+
EXPECT_TRUE(SS_0 != SS_1);
115134

116-
SS(A, B);
117-
EXPECT_EQ(B, "Local::Local");
135+
TestOrder TO_1 = FuncPtr<TestOrder>(
136+
DynamicLibrary::SearchForAddressOfSymbol("TestOrder"));
137+
EXPECT_TRUE(TO_1 != nullptr);
138+
EXPECT_TRUE(TO_0 != TO_1);
139+
140+
B.clear();
141+
SS_1(C, B);
142+
EXPECT_EQ(B, "Local::Local(SecondLib)");
143+
144+
TO_0(Order);
145+
TO_1(Order);
118146
}
119147
EXPECT_EQ(A, "Global::~Global");
120148
EXPECT_EQ(B, "Local::~Local");
121149
EXPECT_TRUE(FuncPtr<SetStrings>(DynamicLibrary::SearchForAddressOfSymbol(
122150
"SetStrings")) == nullptr);
151+
152+
// Test unload/destruction ordering
153+
EXPECT_EQ(Order.size(), 2UL);
154+
EXPECT_EQ(Order.front(), "SecondLib");
155+
EXPECT_EQ(Order.back(), "PipSqueak");
123156
}
124157

125158
#else

llvm/unittests/Support/DynamicLibrary/PipSqueak.cxx

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,40 @@
99

1010
#include "PipSqueak.h"
1111

12-
#if defined(_WIN32) && !defined(__GNUC__)
13-
// Disable warnings from inclusion of xlocale & exception
14-
#pragma warning(push)
15-
#pragma warning(disable: 4530)
16-
#pragma warning(disable: 4577)
17-
#include <string>
18-
#pragma warning(pop)
19-
#else
20-
#include <string>
21-
#endif
22-
2312
struct Global {
2413
std::string *Str;
25-
Global() : Str(nullptr) {}
14+
std::vector<std::string> *Vec;
15+
Global() : Str(nullptr), Vec(nullptr) {}
2616
~Global() {
27-
if (Str)
17+
if (Str) {
18+
if (Vec)
19+
Vec->push_back(*Str);
2820
*Str = "Global::~Global";
21+
}
2922
}
3023
};
3124

25+
static Global Glb;
26+
3227
struct Local {
3328
std::string &Str;
34-
Local(std::string &S) : Str(S) { Str = "Local::Local"; }
29+
Local(std::string &S) : Str(S) {
30+
Str = "Local::Local";
31+
if (Glb.Str && !Glb.Str->empty())
32+
Str += std::string("(") + *Glb.Str + std::string(")");
33+
}
3534
~Local() { Str = "Local::~Local"; }
3635
};
3736

38-
static Global Glb;
3937

4038
extern "C" PIPSQUEAK_EXPORT void SetStrings(std::string &GStr,
4139
std::string &LStr) {
42-
static Local Lcl(LStr);
4340
Glb.Str = &GStr;
41+
static Local Lcl(LStr);
42+
}
43+
44+
extern "C" PIPSQUEAK_EXPORT void TestOrder(std::vector<std::string> &V) {
45+
Glb.Vec = &V;
4446
}
4547

4648
extern "C" PIPSQUEAK_EXPORT const char *TestA() { return "LibCall"; }

llvm/unittests/Support/DynamicLibrary/PipSqueak.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@
1010
#ifndef LLVM_PIPSQUEAK_H
1111
#define LLVM_PIPSQUEAK_H
1212

13+
#if defined(_WIN32) && !defined(__GNUC__)
14+
// Disable warnings from inclusion of xlocale & exception
15+
#pragma warning(push)
16+
#pragma warning(disable: 4530)
17+
#pragma warning(disable: 4577)
18+
#include <string>
19+
#include <vector>
20+
#pragma warning(pop)
21+
#else
22+
#include <string>
23+
#include <vector>
24+
#endif
25+
1326
#ifdef _WIN32
1427
#define PIPSQUEAK_EXPORT __declspec(dllexport)
1528
#else

0 commit comments

Comments
 (0)