Skip to content

Commit 1fd3ae4

Browse files
committed
Expand testing coverage to cover the dynamic library manager
1 parent cc70791 commit 1fd3ae4

File tree

7 files changed

+99
-18
lines changed

7 files changed

+99
-18
lines changed

include/clang/Interpreter/CppInterOp.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,10 @@ namespace Cpp {
340340
/// Checks if the provided parameter is a 'Static' method.
341341
bool IsStaticMethod(TCppConstFunction_t method);
342342

343-
/// Gets the address of the function to be able to call it.
343+
///\returns the address of the function given its potentially mangled name.
344+
TCppFuncAddr_t GetFunctionAddress(const char* mangled_name);
345+
346+
///\returns the address of the function given its function declaration.
344347
TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method);
345348

346349
/// Checks if the provided parameter is a 'Virtual' method.
@@ -461,9 +464,21 @@ namespace Cpp {
461464
///\returns the path to the library.
462465
const std::string LookupLibrary(const char *lib_name);
463466

464-
/// Loads the library based on the path returned by the LookupLibrary()
467+
/// Finds \c lib_stem considering the list of search paths and loads it by
468+
/// calling dlopen.
469+
/// \returns true on success.
470+
bool LoadLibrary(const char* lib_stem, bool lookup = true);
471+
472+
/// Finds \c lib_stem considering the list of search paths and unloads it by
473+
/// calling dlclose.
465474
/// function.
466-
bool LoadLibrary(const char *lib_path, bool lookup = true);
475+
void UnloadLibrary(const char* lib_stem);
476+
477+
/// Scans all libraries on the library search path for a given potentially
478+
/// mangled symbol name.
479+
///\returns the path to the first library that contains the symbol definition.
480+
std::string SearchLibrariesForSymbol(const char* mangled_name,
481+
bool search_system /*true*/);
467482

468483
/// Inserts or replaces a symbol in the JIT with the one provided. This is
469484
/// useful for providing our own implementations of facilities such as printf.

lib/Interpreter/Compatibility.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ inline llvm::orc::LLJIT* getExecutionEngine(const cling::Interpreter& I) {
4646
// to directly.
4747

4848
// sizeof (m_Opts) + sizeof(m_LLVMContext)
49+
#ifdef __APPLE__
50+
const unsigned m_ExecutorOffset = 62;
51+
#else
4952
const unsigned m_ExecutorOffset = 72;
53+
#endif // __APPLE__
5054
int* IncrementalExecutor =
5155
((int*)(const_cast<cling::Interpreter*>(&I))) + m_ExecutorOffset;
5256
int* IncrementalJit = *(int**)IncrementalExecutor + 0;

lib/Interpreter/CppInterOp.cpp

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,17 @@ namespace Cpp {
980980
return false;
981981
}
982982

983+
TCppFuncAddr_t GetFunctionAddress(const char* mangled_name) {
984+
auto& I = getInterp();
985+
auto FDAorErr = compat::getSymbolAddress(I, mangled_name);
986+
if (llvm::Error Err = FDAorErr.takeError())
987+
llvm::consumeError(std::move(Err)); // nullptr if missing
988+
else
989+
return llvm::jitTargetAddressToPointer<void*>(*FDAorErr);
990+
991+
return nullptr;
992+
}
993+
983994
TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method)
984995
{
985996
auto *D = (Decl *) method;
@@ -1002,14 +1013,8 @@ namespace Cpp {
10021013
return mangled_name;
10031014
};
10041015

1005-
auto &I = getInterp();
1006-
if (auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
1007-
auto FDAorErr = compat::getSymbolAddress(I, StringRef(get_mangled_name(FD)));
1008-
if (llvm::Error Err = FDAorErr.takeError())
1009-
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "Failed to GetFunctionAdress:");
1010-
else
1011-
return llvm::jitTargetAddressToPointer<void*>(*FDAorErr);
1012-
}
1016+
if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
1017+
return GetFunctionAddress(get_mangled_name(FD).c_str());
10131018

10141019
return 0;
10151020
}
@@ -2588,13 +2593,23 @@ namespace Cpp {
25882593
return getInterp().getDynamicLibraryManager()->lookupLibrary(lib_name);
25892594
}
25902595

2591-
bool LoadLibrary(const char *lib_name, bool lookup) {
2596+
bool LoadLibrary(const char* lib_stem, bool lookup) {
25922597
compat::Interpreter::CompilationResult res =
2593-
getInterp().loadLibrary(lib_name, lookup);
2598+
getInterp().loadLibrary(lib_stem, lookup);
25942599

25952600
return res == compat::Interpreter::kSuccess;
25962601
}
25972602

2603+
void UnloadLibrary(const char* lib_stem) {
2604+
getInterp().getDynamicLibraryManager()->unloadLibrary(lib_stem);
2605+
}
2606+
2607+
std::string SearchLibrariesForSymbol(const char* mangled_name,
2608+
bool search_system /*true*/) {
2609+
auto* DLM = getInterp().getDynamicLibraryManager();
2610+
return DLM->searchLibrariesForSymbol(mangled_name, search_system);
2611+
}
2612+
25982613
bool InsertOrReplaceJitSymbol(const char* linker_mangled_name,
25992614
uint64_t address) {
26002615
// FIXME: This approach is problematic since we could replace a symbol

lib/Interpreter/CppInterOpInterpreter.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,12 @@ class Interpreter {
330330

331331
const DynamicLibraryManager* getDynamicLibraryManager() const {
332332
assert(compat::getExecutionEngine(*inner) && "We must have an executor");
333-
static const DynamicLibraryManager* DLM = new DynamicLibraryManager();
334-
return DLM;
333+
static std::unique_ptr<DynamicLibraryManager> DLM = nullptr;
334+
if (!DLM) {
335+
DLM.reset(new DynamicLibraryManager());
336+
DLM->initializeDyld([](llvm::StringRef) { /*ignore*/ return false; });
337+
}
338+
return DLM.get();
335339
// TODO: Add DLM to InternalExecutor and use executor->getDML()
336340
// return inner->getExecutionEngine()->getDynamicLibraryManager();
337341
}

unittests/CppInterOp/DynamicLibraryManagerTest.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,49 @@
22

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

5+
#include "llvm/Support/FileSystem.h"
6+
#include "llvm/Support/Path.h"
7+
8+
// This function isn't referenced outside its translation unit, but it
9+
// can't use the "static" keyword because its address is used for
10+
// GetMainExecutable (since some platforms don't support taking the
11+
// address of main, and some platforms can't implement GetMainExecutable
12+
// without being given the address of a function in the main executable).
13+
std::string GetExecutablePath(const char* Argv0) {
14+
// This just needs to be some symbol in the binary; C++ doesn't
15+
// allow taking the address of ::main however.
16+
void* MainAddr = (void*)intptr_t(GetExecutablePath);
17+
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
18+
}
19+
520
TEST(DynamicLibraryManagerTest, Sanity) {
621
EXPECT_TRUE(Cpp::CreateInterpreter());
7-
EXPECT_TRUE(Cpp::LoadLibrary("TestSharedLib"));
22+
EXPECT_FALSE(Cpp::GetFunctionAddress("ret_zero"));
23+
24+
std::string BinaryPath = GetExecutablePath(/*Argv0=*/nullptr);
25+
llvm::StringRef Dir = llvm::sys::path::parent_path(BinaryPath);
26+
Cpp::AddSearchPath(Dir.str().c_str());
27+
28+
// FIXME: dlsym on mach-o takes the C-level name, however, the macho-o format
29+
// adds an additional underscore (_) prefix to the lowered names. Figure out
30+
// how to harmonize that API.
31+
#ifdef __APPLE__
32+
std::string PathToTestSharedLib =
33+
Cpp::SearchLibrariesForSymbol("_ret_zero", /*system_search=*/false);
34+
#else
35+
std::string PathToTestSharedLib =
36+
Cpp::SearchLibrariesForSymbol("ret_zero", /*system_search=*/false);
37+
#endif // __APPLE__
38+
39+
EXPECT_STRNE("", PathToTestSharedLib.c_str())
40+
<< "Cannot find: '" << PathToTestSharedLib << "' in '" << Dir.str()
41+
<< "'";
42+
43+
EXPECT_TRUE(Cpp::LoadLibrary(PathToTestSharedLib.c_str()));
44+
EXPECT_TRUE(Cpp::GetFunctionAddress("ret_zero"));
45+
Cpp::UnloadLibrary("TestSharedLib");
46+
// We have no reliable way to check if it was unloaded because posix does not
47+
// require the library to be actually unloaded but just the handle to be
48+
// invalidated...
49+
// EXPECT_FALSE(Cpp::GetFunctionAddress("ret_zero"));
850
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB_H
22
#define UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB_H
33

4-
int ret_zero();
4+
// Avoid having to mangle/demangle the symbol name in tests.
5+
extern "C" int ret_zero();
56

67
#endif // UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB_H

unittests/CppInterOp/Utils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef CPPINTEROP_UNITTESTS_LIBCPPINTEROP_UTILS_H
22
#define CPPINTEROP_UNITTESTS_LIBCPPINTEROP_UTILS_H
33

4-
#include "../../../lib/Interpreter/Compatibility.h"
4+
#include "../../lib/Interpreter/Compatibility.h"
55

66
#include <memory>
77
#include <vector>

0 commit comments

Comments
 (0)