diff options
author | Frederich Munch <colsebas@hotmail.com> | 2017-04-24 02:30:12 +0000 |
---|---|---|
committer | Frederich Munch <colsebas@hotmail.com> | 2017-04-24 02:30:12 +0000 |
commit | 9f40457d61dc8285e454d688e9062c5813299341 (patch) | |
tree | 6e5120defd9628318c05250ed5e7fc4f63e935b6 /llvm/unittests/Support/DynamicLibrary | |
parent | fe3c21c8797e7fe12b4c9727ae6d4e70236c869a (diff) | |
download | bcm5719-llvm-9f40457d61dc8285e454d688e9062c5813299341.tar.gz bcm5719-llvm-9f40457d61dc8285e454d688e9062c5813299341.zip |
Refactor DynamicLibrary so searching for a symbol will have a defined order and
libraries are properly unloaded when llvm_shutdown is called.
Summary:
This was mostly affecting usage of the JIT, where storing the library handles in
a set made iteration unordered/undefined. This lead to disagreement between the
JIT and native code as to what the address and implementation of particularly on
Windows with stdlib functions:
JIT: putenv_s("TEST", "VALUE") // called msvcrt.dll, putenv_s
JIT: getenv("TEST") -> "VALUE" // called msvcrt.dll, getenv
Native: getenv("TEST") -> NULL // called ucrt.dll, getenv
Also fixed is the issue of DynamicLibrary::getPermanentLibrary(0,0) on Windows
not giving priority to the process' symbols as it did on Unix.
Reviewers: chapuni, v.g.vassilev, lhames
Reviewed By: lhames
Subscribers: danalbert, srhines, mgorny, vsk, llvm-commits
Differential Revision: https://reviews.llvm.org/D30107
llvm-svn: 301153
Diffstat (limited to 'llvm/unittests/Support/DynamicLibrary')
4 files changed, 207 insertions, 0 deletions
diff --git a/llvm/unittests/Support/DynamicLibrary/CMakeLists.txt b/llvm/unittests/Support/DynamicLibrary/CMakeLists.txt new file mode 100644 index 00000000000..f0e945e78b1 --- /dev/null +++ b/llvm/unittests/Support/DynamicLibrary/CMakeLists.txt @@ -0,0 +1,19 @@ +set(LLVM_LINK_COMPONENTS Support) + +add_llvm_unittest(DynamicLibraryTests DynamicLibraryTest.cpp) + +export_executable_symbols(DynamicLibraryTests) + +add_library(PipSqueak SHARED PipSqueak.cxx) + +set_output_directory(PipSqueak + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} + LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} + ) + +set_target_properties(PipSqueak + PROPERTIES PREFIX "" + SUFFIX ".so" + ) + +add_dependencies(DynamicLibraryTests PipSqueak) diff --git a/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp b/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp new file mode 100644 index 00000000000..793cd621d1c --- /dev/null +++ b/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp @@ -0,0 +1,133 @@ +//===- llvm/unittest/Support/DynamicLibrary/DynamicLibraryTest.cpp --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "gtest/gtest.h" + +#include "PipSqueak.h" +#include <string> + +using namespace llvm; +using namespace llvm::sys; + +extern "C" PIPSQUEAK_EXPORT const char *TestA() { return "ProcessCall"; } + +std::string LibPath() { + std::string Path = + fs::getMainExecutable("DynamicLibraryTests", (void *)&TestA); + llvm::SmallString<256> Buf(path::parent_path(Path)); + path::append(Buf, "PipSqueak.so"); + return Buf.str(); +} + +#if defined(_WIN32) || (defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN)) + +typedef void (*SetStrings)(std::string &GStr, std::string &LStr); +typedef const char *(*GetString)(); + +template <class T> static T FuncPtr(void *Ptr) { + union { + T F; + void *P; + } Tmp; + Tmp.P = Ptr; + return Tmp.F; +} +template <class T> static void* PtrFunc(T *Func) { + union { + T *F; + void *P; + } Tmp; + Tmp.F = Func; + return Tmp.P; +} + +static const char *OverloadTestA() { return "OverloadCall"; } + +std::string StdString(const char *Ptr) { return Ptr ? Ptr : ""; } + +TEST(DynamicLibrary, Overload) { + { + std::string Err; + llvm_shutdown_obj Shutdown; + DynamicLibrary DL = + DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err); + EXPECT_TRUE(DL.isValid()); + EXPECT_TRUE(Err.empty()); + + GetString GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA")); + EXPECT_TRUE(GS != nullptr && GS != &TestA); + EXPECT_EQ(StdString(GS()), "LibCall"); + + GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); + EXPECT_TRUE(GS != nullptr && GS != &TestA); + EXPECT_EQ(StdString(GS()), "LibCall"); + + DL = DynamicLibrary::getPermanentLibrary(nullptr, &Err); + EXPECT_TRUE(DL.isValid()); + EXPECT_TRUE(Err.empty()); + + GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); + EXPECT_TRUE(GS != nullptr && GS == &TestA); + EXPECT_EQ(StdString(GS()), "ProcessCall"); + + GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA")); + EXPECT_TRUE(GS != nullptr && GS == &TestA); + EXPECT_EQ(StdString(GS()), "ProcessCall"); + + DynamicLibrary::AddSymbol("TestA", PtrFunc(&OverloadTestA)); + GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA")); + EXPECT_TRUE(GS != nullptr && GS != &OverloadTestA); + + GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA")); + EXPECT_TRUE(GS != nullptr && GS == &OverloadTestA); + EXPECT_EQ(StdString(GS()), "OverloadCall"); + } + EXPECT_TRUE(FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol( + "TestA")) == nullptr); +} + +TEST(DynamicLibrary, Shutdown) { + std::string A, B; + { + std::string Err; + llvm_shutdown_obj Shutdown; + DynamicLibrary DL = + DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err); + EXPECT_TRUE(DL.isValid()); + EXPECT_TRUE(Err.empty()); + + SetStrings SS = FuncPtr<SetStrings>( + DynamicLibrary::SearchForAddressOfSymbol("SetStrings")); + EXPECT_TRUE(SS != nullptr); + + SS(A, B); + EXPECT_EQ(B, "Local::Local"); + } + EXPECT_EQ(A, "Global::~Global"); + EXPECT_EQ(B, "Local::~Local"); + EXPECT_TRUE(FuncPtr<SetStrings>(DynamicLibrary::SearchForAddressOfSymbol( + "SetStrings")) == nullptr); +} + +#else + +TEST(DynamicLibrary, Unsupported) { + std::string Err; + DynamicLibrary DL = + DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err); + EXPECT_FALSE(DL.isValid()); + EXPECT_EQ(Err, "dlopen() not supported on this platform"); +} + +#endif diff --git a/llvm/unittests/Support/DynamicLibrary/PipSqueak.cxx b/llvm/unittests/Support/DynamicLibrary/PipSqueak.cxx new file mode 100644 index 00000000000..1de85236a88 --- /dev/null +++ b/llvm/unittests/Support/DynamicLibrary/PipSqueak.cxx @@ -0,0 +1,36 @@ +//===- llvm/unittest/Support/DynamicLibrary/PipSqueak.cxx -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PipSqueak.h" +#include <string> + +struct Global { + std::string *Str; + Global() : Str(nullptr) {} + ~Global() { + if (Str) + *Str = "Global::~Global"; + } +}; + +struct Local { + std::string &Str; + Local(std::string &S) : Str(S) { Str = "Local::Local"; } + ~Local() { Str = "Local::~Local"; } +}; + +static Global Glb; + +extern "C" PIPSQUEAK_EXPORT void SetStrings(std::string &GStr, + std::string &LStr) { + static Local Lcl(LStr); + Glb.Str = &GStr; +} + +extern "C" PIPSQUEAK_EXPORT const char *TestA() { return "LibCall"; } diff --git a/llvm/unittests/Support/DynamicLibrary/PipSqueak.h b/llvm/unittests/Support/DynamicLibrary/PipSqueak.h new file mode 100644 index 00000000000..e6a859d6071 --- /dev/null +++ b/llvm/unittests/Support/DynamicLibrary/PipSqueak.h @@ -0,0 +1,19 @@ +//===- llvm/unittest/Support/DynamicLibrary/PipSqueak.h -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PIPSQUEAK_H +#define LLVM_PIPSQUEAK_H + +#ifdef _WIN32 +#define PIPSQUEAK_EXPORT __declspec(dllexport) +#else +#define PIPSQUEAK_EXPORT +#endif + +#endif |