Changeset View
Changeset View
Standalone View
Standalone View
test/dlopen_dynamic_cast.sh.cpp
- This file was added.
//===-------------------- dlopen_dynamic_cast.sh.cpp ----------------------===// | |||||
// | |||||
// The LLVM Compiler Infrastructure | |||||
// | |||||
// This file is dual licensed under the MIT and the University of Illinois Open | |||||
// Source Licenses. See LICENSE.TXT for details. | |||||
// | |||||
//===----------------------------------------------------------------------===// | |||||
// type_infos are not coalesced across dlopen boundaries when RTLD_LOCAL is | |||||
// used, as is common in plugin interfaces and JNI libraries. For dynamic_cast | |||||
// to work across a dlopen boundary, we must use a string comparison of the type | |||||
// names instead of a pointer comparison of the type_infos. | |||||
// https://reviews.llvm.org/D38599 | |||||
// XFAIL: libcxx-no-dynamic-fallback | |||||
// RUN: %cxx %flags %compile_flags -DBUILD_BASE -fPIC -c %s -o %T/base.o | |||||
// RUN: %cxx %flags %link_flags -shared %T/base.o -o %T/libbase.so | |||||
// RUN: %cxx %flags %compile_flags -DBUILD_TEST -fPIC -c %s -o %T/test.o | |||||
// RUN: %cxx %flags %link_flags -shared %T/test.o -o %T/libtest.so -L%T -lbase | |||||
// RUN: %cxx %flags %compile_flags -DBUILD_EXE -c %s -o %t.o | |||||
// RUN: %cxx %flags %link_flags %t.o -o %t.exe -ldl | |||||
// RUN: LD_LIBRARY_PATH=%T %t.exe | |||||
class Base { | |||||
public: | |||||
virtual ~Base(){}; | |||||
}; | |||||
class BaseImpl : public Base { | |||||
public: | |||||
BaseImpl(); | |||||
}; | |||||
#ifdef BUILD_BASE | |||||
BaseImpl::BaseImpl() {} | |||||
#endif | |||||
#ifdef BUILD_TEST | |||||
extern "C" bool do_test() { | |||||
BaseImpl base_impl; | |||||
Base* base = &base_impl; | |||||
return dynamic_cast<BaseImpl*>(base) != nullptr; | |||||
} | |||||
#endif | |||||
#ifdef BUILD_EXE | |||||
#include <dlfcn.h> | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
typedef bool (*test_func)(); | |||||
void* load_library(const char* name) { | |||||
void* lib = dlopen(name, RTLD_NOW | RTLD_LOCAL); | |||||
if (lib == nullptr) { | |||||
fprintf(stderr, "dlopen %s failed: %s\n", name, dlerror()); | |||||
abort(); | |||||
} | |||||
return lib; | |||||
} | |||||
test_func load_func(void* lib, const char* name) { | |||||
test_func sym = reinterpret_cast<test_func>(dlsym(lib, name)); | |||||
if (sym == nullptr) { | |||||
fprintf(stderr, "dlsym %s failed: %s\n", name, dlerror()); | |||||
abort(); | |||||
} | |||||
return sym; | |||||
} | |||||
int main(int argc, char**) { | |||||
// Explicitly loading libbase.so before libtest.so causes the test to fail | |||||
// because the type_infos do not get coalesced. | |||||
load_library("libbase.so"); | |||||
void* libtest = load_library("libtest.so"); | |||||
test_func do_test = load_func(libtest, "do_test"); | |||||
if (!do_test()) { | |||||
fprintf(stderr, "do_test() failed!\n"); | |||||
return EXIT_FAILURE; | |||||
} else { | |||||
fprintf(stderr, "do_test() passed!\n"); | |||||
return EXIT_SUCCESS; | |||||
} | |||||
} | |||||
#endif |