Skip to content

Commit ae4b0ab

Browse files
Fix
1 parent 1cbc857 commit ae4b0ab

File tree

10 files changed

+213
-62
lines changed

10 files changed

+213
-62
lines changed

include/clang/Interpreter/CppInterOp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ namespace Cpp {
761761
///\param[in] autoload - true = libraries autoload is on.
762762
CPPINTEROP_API void SetLibrariesAutoload(bool autoload = true);
763763

764-
/// Get libraries autoload.
764+
/// Get libraries autoload status.
765765
///\returns LibraryAutoLoad state (true = libraries autoload is on).
766766
CPPINTEROP_API bool GetLibrariesAutoload();
767767

lib/Interpreter/CppInterOp.cpp

Lines changed: 39 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,9 +1137,9 @@ namespace Cpp {
11371137
auto FDAorErr = compat::getSymbolAddress(I, mangled_name);
11381138
if (llvm::Error Err = FDAorErr.takeError())
11391139
llvm::consumeError(std::move(Err)); // nullptr if missing
1140-
else
1140+
else {
11411141
return llvm::jitTargetAddressToPointer<void*>(*FDAorErr);
1142-
1142+
}
11431143
return nullptr;
11441144
}
11451145

@@ -2730,7 +2730,7 @@ namespace Cpp {
27302730
std::string BinaryPath = GetExecutablePath(/*Argv0=*/nullptr, MainAddr);
27312731

27322732
// build/tools/clang/unittests/Interpreter/Executable -> build/
2733-
StringRef Dir = sys::path::parent_path(BinaryPath);
2733+
Dir = sys::path::parent_path(BinaryPath);
27342734

27352735
Dir = sys::path::parent_path(Dir);
27362736
Dir = sys::path::parent_path(Dir);
@@ -3565,12 +3565,6 @@ namespace Cpp {
35653565
return nameForDlsym;
35663566
}
35673567

3568-
class AutoLoadLibrarySearchGenerator;
3569-
3570-
// Last assigned Autoload SearchGenerator
3571-
// TODO: Test for thread safe.
3572-
static AutoLoadLibrarySearchGenerator *AutoSG = nullptr;
3573-
35743568
class AutoLoadLibrarySearchGenerator : public llvm::orc::DefinitionGenerator {
35753569
bool Enabled = false;
35763570
public:
@@ -3587,15 +3581,15 @@ namespace Cpp {
35873581
std::string lib;
35883582
llvm::orc::SymbolNameVector syms;
35893583
public:
3590-
AutoloadLibraryMU(const std::string& Library, const llvm::orc::SymbolNameVector &Symbols)
3591-
: MaterializationUnit({getSymbolFlagsMap(Symbols), nullptr}), lib(Library), syms(Symbols) {}
3584+
AutoloadLibraryMU(std::string Library, const llvm::orc::SymbolNameVector &Symbols)
3585+
: MaterializationUnit({getSymbolFlagsMap(Symbols), nullptr}), lib(std::move(Library)), syms(Symbols) {}
35923586

3593-
[[nodiscard]] StringRef getName() const override {
3587+
StringRef getName() const override {
35943588
return "<Symbols from Autoloaded Library>";
35953589
}
35963590

35973591
void materialize(std::unique_ptr<llvm::orc::MaterializationResponsibility> R) override {
3598-
if (!AutoSG || !AutoSG->isEnabled()) {
3592+
if (!sAutoSG || !sAutoSG->isEnabled()) {
35993593
R->failMaterialization();
36003594
return;
36013595
}
@@ -3669,37 +3663,37 @@ namespace Cpp {
36693663

36703664
llvm::Error tryToGenerate(llvm::orc::LookupState &LS, llvm::orc::LookupKind K, llvm::orc::JITDylib &JD,
36713665
llvm::orc::JITDylibLookupFlags JDLookupFlags, const llvm::orc::SymbolLookupSet &Symbols) override {
3672-
if (isEnabled()) {
3673-
LLVM_DEBUG(dbgs() << "tryToGenerate");
3666+
if (!isEnabled())
3667+
return llvm::Error::success();
3668+
LLVM_DEBUG(dbgs() << "tryToGenerate");
36743669

3675-
auto& I = getInterp();
3676-
auto *DLM = I.getDynamicLibraryManager();
3670+
auto& I = getInterp();
3671+
auto *DLM = I.getDynamicLibraryManager();
36773672

3678-
std::unordered_map<std::string, llvm::orc::SymbolNameVector> found;
3679-
llvm::orc::SymbolMap NewSymbols;
3680-
for (const auto &KV : Symbols) {
3681-
const auto &Name = KV.first;
3682-
if ((*Name).empty())
3683-
continue;
3673+
std::unordered_map<std::string, llvm::orc::SymbolNameVector> found;
3674+
llvm::orc::SymbolMap NewSymbols;
3675+
for (const auto &KV : Symbols) {
3676+
const auto &Name = KV.first;
3677+
if ((*Name).empty())
3678+
continue;
36843679

3685-
auto lib = DLM->searchLibrariesForSymbol(*Name, /*searchSystem=*/true); // false?
3686-
if (lib.empty())
3687-
continue;
3680+
auto lib = DLM->searchLibrariesForSymbol(*Name, /*searchSystem=*/true); // false?
3681+
if (lib.empty())
3682+
continue;
36883683

3689-
found[lib].push_back(Name);
3684+
found[lib].push_back(Name);
36903685

3691-
// Workaround: This getAddressOfGlobal call make first symbol search
3692-
// to work, immediatelly after library auto load. This approach do not
3693-
// use MU
3694-
//DLM->loadLibrary(lib, true);
3695-
//I.getAddressOfGlobal(*Name);
3696-
}
3686+
// Workaround: This getAddressOfGlobal call make first symbol search
3687+
// to work, immediatelly after library auto load. This approach do not
3688+
// use MU
3689+
//DLM->loadLibrary(lib, true);
3690+
//I.getAddressOfGlobal(*Name);
3691+
}
36973692

3698-
for (auto &&KV : found) {
3699-
auto MU = std::make_unique<AutoloadLibraryMU>(KV.first, std::move(KV.second));
3700-
if (auto Err = JD.define(MU))
3701-
return Err;
3702-
}
3693+
for (auto &&KV : found) {
3694+
auto MU = std::make_unique<AutoloadLibraryMU>(KV.first, std::move(KV.second));
3695+
if (auto Err = JD.define(MU))
3696+
return Err;
37033697
}
37043698

37053699
return llvm::Error::success();
@@ -3716,16 +3710,17 @@ namespace Cpp {
37163710
llvm::orc::JITDylib& DyLib = *EE.getProcessSymbolsJITDylib().get();
37173711
#endif // CLANG_VERSION_MAJOR
37183712

3719-
if (!AutoSG)
3720-
AutoSG = &DyLib.addGenerator(std::make_unique<AutoLoadLibrarySearchGenerator>());
3721-
AutoSG->setEnabled(autoload);
3713+
if (!sAutoSG) {
3714+
sAutoSG = &DyLib.addGenerator(std::make_unique<AutoLoadLibrarySearchGenerator>());
3715+
}
3716+
sAutoSG->setEnabled(autoload);
37223717

3723-
LLVM_DEBUG(dbgs() << "Autoload=" << (AutoSG->isEnabled() ? "ON" : "OFF"));
3718+
LLVM_DEBUG(dbgs() << "Autoload=" << (sAutoSG->isEnabled() ? "ON" : "OFF"));
37243719
}
37253720

37263721
bool GetLibrariesAutoload() {
3727-
LLVM_DEBUG(dbgs() << "Autoload is " << (AutoSG && AutoSG->isEnabled() ? "ON" : "OFF"));
3728-
return AutoSG && AutoSG->isEnabled();
3722+
LLVM_DEBUG(dbgs() << "Autoload is " << (sAutoSG && sAutoSG->isEnabled() ? "ON" : "OFF"));
3723+
return sAutoSG && sAutoSG->isEnabled();
37293724
}
37303725

37313726
#undef DEBUG_TYPE

unittests/CppInterOp/CMakeLists.txt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,28 @@ target_link_libraries(DynamicLibraryManagerTests
4343
clangCppInterOp
4444
)
4545

46+
set_source_files_properties(DynamicLibraryManagerTest.cpp PROPERTIES COMPILE_DEFINITIONS
47+
"LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\""
48+
)
49+
set_source_files_properties(DynamicLibraryManagerTest.cpp PROPERTIES COMPILE_DEFINITIONS
50+
"CPPINTEROP_VERSION=\"${CPPINTEROP_VERSION}\""
51+
)
52+
53+
set_output_directory(DynamicLibraryManagerTests BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/TestSharedLib/unittests/bin/$<CONFIG>/)
54+
4655
set_output_directory(DynamicLibraryManagerTests
4756
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/TestSharedLib/unittests/bin/$<CONFIG>/
4857
LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/TestSharedLib/unittests/bin/$<CONFIG>/
4958
)
5059
add_dependencies(DynamicLibraryManagerTests TestSharedLib)
5160
#export_executable_symbols_for_plugins(TestSharedLib)
5261
add_subdirectory(TestSharedLib)
53-
# TODO: Remove when libraryunload work correctly
5462
add_dependencies(DynamicLibraryManagerTests TestSharedLib1)
5563
#export_executable_symbols_for_plugins(TestSharedLib1)
5664
add_subdirectory(TestSharedLib1)
65+
add_dependencies(DynamicLibraryManagerTests TestSharedLib2)
66+
#export_executable_symbols_for_plugins(TestSharedLib2)
67+
add_subdirectory(TestSharedLib2)
68+
add_dependencies(DynamicLibraryManagerTests TestSharedLib3)
69+
#export_executable_symbols_for_plugins(TestSharedLib3)
70+
add_subdirectory(TestSharedLib3)

unittests/CppInterOp/DynamicLibraryManagerTest.cpp

Lines changed: 104 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
#include "clang/Interpreter/CppInterOp.h"
44

5+
6+
#include "llvm/ExecutionEngine/Orc/Core.h"
7+
#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
58
#include "llvm/Support/FileSystem.h"
69
#include "llvm/Support/Path.h"
7-
10+
#include "llvm/Support/raw_ostream.h"
811

912
// Helper functions
1013

@@ -13,13 +16,14 @@
1316
// GetMainExecutable (since some platforms don't support taking the
1417
// address of main, and some platforms can't implement GetMainExecutable
1518
// without being given the address of a function in the main executable).
16-
std::string GetExecutablePath(const char* Argv0) {
19+
std::string GetExecutablePath(const char* Argv0, void* mainAddr = nullptr) {
1720
// This just needs to be some symbol in the binary; C++ doesn't
1821
// allow taking the address of ::main however.
19-
void* MainAddr = (void*)intptr_t(GetExecutablePath);
22+
void* MainAddr = mainAddr ? mainAddr : (void*)intptr_t(GetExecutablePath);
2023
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
2124
}
2225

26+
// Mangle symbol name
2327
static inline std::string MangleNameForDlsym(const std::string& name) {
2428
std::string nameForDlsym = name;
2529
#if defined(R__MACOSX) || defined(R__WIN32)
@@ -29,30 +33,33 @@ static inline std::string MangleNameForDlsym(const std::string& name) {
2933
return nameForDlsym;
3034
}
3135

36+
#include "../../lib/Interpreter/CppInterOp.cpp"
37+
38+
3239
// Tests
3340

3441
TEST(DynamicLibraryManagerTest, Sanity) {
3542
EXPECT_TRUE(Cpp::CreateInterpreter());
3643
EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_zero").c_str()));
3744

38-
std::string BinaryPath = GetExecutablePath(/*Argv0=*/nullptr);
45+
std::string BinaryPath = GetExecutablePath(nullptr, nullptr);
3946
llvm::StringRef Dir = llvm::sys::path::parent_path(BinaryPath);
4047
Cpp::AddSearchPath(Dir.str().c_str());
4148

49+
// Find and load library with "ret_zero" symbol defined and exported
50+
//
4251
// FIXME: dlsym on mach-o takes the C-level name, however, the macho-o format
4352
// adds an additional underscore (_) prefix to the lowered names. Figure out
4453
// how to harmonize that API.
45-
4654
std::string PathToTestSharedLib =
4755
Cpp::SearchLibrariesForSymbol(MangleNameForDlsym("ret_zero").c_str(), /*system_search=*/false);
48-
4956
EXPECT_STRNE("", PathToTestSharedLib.c_str())
50-
<< "Cannot find: '" << PathToTestSharedLib << "' in '" << Dir.str()
51-
<< "'";
52-
57+
<< "Cannot find: '" << PathToTestSharedLib << "' in '" << Dir.str() << "'";
5358
EXPECT_TRUE(Cpp::LoadLibrary(PathToTestSharedLib.c_str()));
59+
5460
// Force ExecutionEngine to be created.
5561
Cpp::Process("");
62+
5663
// FIXME: Conda returns false to run this code on osx.
5764
EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_zero").c_str()));
5865

@@ -70,19 +77,18 @@ TEST(DynamicLibraryManagerTest, LibrariesAutoload) {
7077
EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str()));
7178

7279
// Libraries Search path by default is set to main executable directory.
73-
std::string BinaryPath = GetExecutablePath(/*Argv0=*/nullptr);
80+
std::string BinaryPath = GetExecutablePath(nullptr, nullptr);
7481
llvm::StringRef Dir = llvm::sys::path::parent_path(BinaryPath);
7582
Cpp::AddSearchPath(Dir.str().c_str());
7683

77-
// Find library with "rec_one" symbol defined and exported
84+
// Find library with "ret_one" symbol defined and exported
7885
//
7986
// FIXME: dlsym on mach-o takes the C-level name, however, the macho-o format
8087
// adds an additional underscore (_) prefix to the lowered names. Figure out
8188
// how to harmonize that API. For now we use out minimal implementation of
8289
// helper function.
8390
std::string PathToTestSharedLib1 =
8491
Cpp::SearchLibrariesForSymbol(MangleNameForDlsym("ret_one").c_str(), /*system_search=*/false);
85-
8692
// If result is "" then we cannot find this library.
8793
EXPECT_STRNE("", PathToTestSharedLib1.c_str())
8894
<< "Cannot find: '" << PathToTestSharedLib1 << "' in '" << Dir.str() << "'";
@@ -117,13 +123,95 @@ TEST(DynamicLibraryManagerTest, LibrariesAutoload) {
117123
Cpp::SetLibrariesAutoload(false);
118124
// Check autorum status (must be turned OFF)
119125
EXPECT_FALSE(Cpp::GetLibrariesAutoload());
120-
//EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str())); // if unload works
121-
//EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str()));
126+
EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str())); // false if unload works
122127

123128
// Autoload turn ON again
124129
Cpp::SetLibrariesAutoload(true);
125130
// Check autorum status (must be turned ON)
126131
EXPECT_TRUE(Cpp::GetLibrariesAutoload());
127-
//EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str())); // if unload works
128-
//EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str()));
132+
EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str()));
133+
134+
// Find library with "ret_1" symbol defined and exported
135+
std::string PathToTestSharedLib2 =
136+
Cpp::SearchLibrariesForSymbol(MangleNameForDlsym("ret_1").c_str(), /*system_search=*/false);
137+
// If result is "" then we cannot find this library.
138+
EXPECT_STRNE("", PathToTestSharedLib2.c_str())
139+
<< "Cannot find: '" << PathToTestSharedLib2 << "' in '" << Dir.str() << "'";
140+
// Find symbol must success (when auotload=on)
141+
EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_1").c_str()));
142+
// Find symbol must success (when auotload=on)
143+
EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_2").c_str()));
144+
}
145+
146+
TEST(DynamicLibraryManagerTest, LibrariesAutoloadExtraCoverage) {
147+
EXPECT_TRUE(Cpp::CreateInterpreter());
148+
149+
// Libraries Search path by default is set to main executable directory.
150+
std::string BinaryPath = GetExecutablePath(nullptr, nullptr);
151+
llvm::StringRef Dir = llvm::sys::path::parent_path(BinaryPath);
152+
Cpp::AddSearchPath(Dir.str().c_str());
153+
154+
// Force ExecutionEngine to be created.
155+
Cpp::Process("");
156+
157+
// Autoload turn ON
158+
Cpp::SetLibrariesAutoload(true);
159+
// Check autorum status (must be turned ON)
160+
EXPECT_TRUE(Cpp::GetLibrariesAutoload());
161+
162+
// Cover: MU getName()
163+
std::string res;
164+
llvm::raw_string_ostream rss(res);
165+
const llvm::orc::SymbolNameVector syms;
166+
Cpp::AutoLoadLibrarySearchGenerator::AutoloadLibraryMU MU("test", syms);
167+
rss << MU;
168+
EXPECT_STRNE("", rss.str().c_str()) << "MU problem!";
169+
170+
// Cover: LoadLibrary error
171+
// if (DLM->loadLibrary(lib, false) != DynamicLibraryManager::LoadLibResult::kLoadLibSuccess) {
172+
// LLVM_DEBUG(dbgs() << "MU: Failed to load library " << lib);
173+
// string err = "MU: Failed to load library! " + lib;
174+
// perror(err.c_str());
175+
// } else {
176+
// Find library with "ret_value" symbol defined and exported
177+
std::string PathToTestSharedLib3 =
178+
Cpp::SearchLibrariesForSymbol(MangleNameForDlsym("ret_val").c_str(), /*system_search=*/false);
179+
// If result is "" then we cannot find this library.
180+
EXPECT_STRNE("", PathToTestSharedLib3.c_str())
181+
<< "Cannot find: '" << PathToTestSharedLib3 << "' in '" << Dir.str() << "'";
182+
// Remove library for simulate load error
183+
llvm::sys::fs::remove(PathToTestSharedLib3, true);
184+
EXPECT_TRUE(Cpp::GetLibrariesAutoload());
185+
// FIXME: Conda returns false to run this code on osx.
186+
EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_val").c_str()));
187+
188+
// Cover
189+
// } else {
190+
// // Collect all failing symbols, delegate their responsibility and then
191+
// // fail their materialization. R->defineNonExistent() sounds like it
192+
// // should do that, but it's not implemented?!
193+
// failedSymbols.insert(symbol);
194+
// TODO: implement test this case
195+
196+
// Cover
197+
// if (!failedSymbols.empty()) {
198+
// auto failingMR = R->delegate(failedSymbols);
199+
// if (failingMR) {
200+
// (*failingMR)->failMaterialization();
201+
// TODO: implement test this case
202+
203+
// Cover
204+
// void discard(const llvm::orc::JITDylib &JD, const llvm::orc::SymbolStringPtr &Name) override {}
205+
// TODO: implement test this case
206+
207+
// Cover
208+
// if (Path.empty()) {
209+
// LLVM_DEBUG(dbgs() << "DynamicLibraryManager::lookupLibMaybeAddExt(): "
210+
// TODO: implement test this case
211+
212+
// Cover
213+
// platform::DLClose(dyLibHandle, &errMsg);
214+
// if (!errMsg.empty()) {
215+
// LLVM_DEBUG(dbgs() << "DynamicLibraryManager::unloadLibrary(): "
216+
// TODO: implement test this case
129217
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
add_llvm_library(TestSharedLib2
2+
SHARED
3+
DISABLE_LLVM_LINK_LLVM_DYLIB
4+
BUILDTREE_ONLY
5+
TestSharedLib2.cpp)
6+
# Put TestSharedLib2 next to the unit test executable.
7+
set_output_directory(TestSharedLib2
8+
BINARY_DIR ${CMAKE_BINARY_DIR}/unittests/bin/$<CONFIG>/
9+
LIBRARY_DIR ${CMAKE_BINARY_DIR}/unittests/bin/$<CONFIG>/
10+
)
11+
set_target_properties(TestSharedLib2 PROPERTIES FOLDER "Tests")
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "TestSharedLib2.h"
2+
3+
int ret_1() { return 1; }
4+
5+
int ret_2() { return 2; }

0 commit comments

Comments
 (0)