danalbert updated this revision to Diff 118711.
danalbert added a comment.
Herald added a subscriber: mgorny.

Update the test with an XFAIL when _LIBCXX_DYNAMIC_FALLBACK is not set.

https://reviews.llvm.org/D38827 adds this cmake option to libc++.


https://reviews.llvm.org/D38599

Files:
  CMakeLists.txt
  src/private_typeinfo.cpp
  test/CMakeLists.txt
  test/dlopen_dynamic_cast.sh.cpp
  test/libcxxabi/test/config.py
  test/lit.site.cfg.in

Index: test/lit.site.cfg.in
===================================================================
--- test/lit.site.cfg.in
+++ test/lit.site.cfg.in
@@ -16,6 +16,7 @@
 config.executor                 = "@LIBCXXABI_EXECUTOR@"
 config.libcxxabi_shared         = "@LIBCXXABI_ENABLE_SHARED@"
 config.enable_shared            = "@LIBCXX_ENABLE_SHARED@"
+config.dynamic_fallback         = "@LIBCXX_DYNAMIC_FALLBACK@"
 config.enable_exceptions        = "@LIBCXXABI_ENABLE_EXCEPTIONS@"
 config.host_triple              = "@LLVM_HOST_TRIPLE@"
 config.target_triple            = "@TARGET_TRIPLE@"
Index: test/libcxxabi/test/config.py
===================================================================
--- test/libcxxabi/test/config.py
+++ test/libcxxabi/test/config.py
@@ -48,6 +48,11 @@
         if not self.get_lit_bool('llvm_unwinder', False):
             self.config.available_features.add('libcxxabi-has-system-unwinder')
 
+        if self.get_lit_bool('dynamic_fallback', False):
+            self.config.available_features.add('libcxx-dynamic-fallback')
+        else:
+            self.config.available_features.add('libcxx-no-dynamic-fallback')
+
     def configure_compile_flags(self):
         self.cxx.compile_flags += ['-DLIBCXXABI_NO_TIMER']
         if self.get_lit_bool('enable_exceptions', True):
Index: test/dlopen_dynamic_cast.sh.cpp
===================================================================
--- /dev/null
+++ test/dlopen_dynamic_cast.sh.cpp
@@ -0,0 +1,89 @@
+//===-------------------- 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
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -18,6 +18,7 @@
 pythonize_bool(LIBCXXABI_ENABLE_EXCEPTIONS)
 pythonize_bool(LIBCXXABI_USE_LLVM_UNWINDER)
 pythonize_bool(LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY)
+pythonize_bool(LIBCXX_DYNAMIC_FALLBACK)
 set(LIBCXXABI_TARGET_INFO "libcxx.test.target_info.LocalTI" CACHE STRING
     "TargetInfo to use when setting up test environment.")
 set(LIBCXXABI_EXECUTOR "None" CACHE STRING
Index: src/private_typeinfo.cpp
===================================================================
--- src/private_typeinfo.cpp
+++ src/private_typeinfo.cpp
@@ -10,39 +10,19 @@
 #include "private_typeinfo.h"
 
 // The flag _LIBCXX_DYNAMIC_FALLBACK is used to make dynamic_cast more
-// forgiving when type_info's mistakenly have hidden visibility and thus
-// multiple type_infos can exist for a single type.
-// 
+// forgiving when multiple type_infos exist for a single type. This happens if
+// the libraries are mistakenly built with the type_infos having hidden
+// visibility, but also occurs when the libraries are loaded with dlopen.
+//
 // When _LIBCXX_DYNAMIC_FALLBACK is defined, and only in the case where
 // there is a detected inconsistency in the type_info hierarchy during a
 // dynamic_cast, then the equality operation will fall back to using strcmp
 // on type_info names to determine type_info equality.
-// 
-// This change happens *only* under dynamic_cast, and only when
-// dynamic_cast is faced with the choice:  abort, or possibly give back the
-// wrong answer.  If when the dynamic_cast is done with this fallback
-// algorithm and an inconsistency is still detected, dynamic_cast will call
-// abort with an appropriate message.
-// 
-// The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a
-// printf-like function called syslog:
-// 
-//     void syslog(int facility_priority, const char* format, ...);
-// 
-// If you want this functionality but your platform doesn't have syslog,
-// just implement it in terms of fprintf(stderr, ...).
-// 
+//
 // _LIBCXX_DYNAMIC_FALLBACK is currently off by default.
 
-
 #include <string.h>
 
-
-#ifdef _LIBCXX_DYNAMIC_FALLBACK
-#include "abort_message.h"
-#include <sys/syslog.h>
-#endif
-
 // On Windows, typeids are different between DLLs and EXEs, so comparing
 // type_info* will work for typeids from the same compiled file but fail
 // for typeids from a DLL and an executable. Among other things, exceptions
@@ -647,11 +627,11 @@
         //   find (static_ptr, static_type), either on a public or private path
         if (info.path_dst_ptr_to_static_ptr == unknown)
         {
-            // We get here only if there is some kind of visibility problem
-            //   in client code.
-            syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
-                    "should have public visibility.  At least one of them is hidden. %s" 
-                    ", %s.\n", static_type->name(), dynamic_type->name());
+            // We get here only if there is some kind of visibility problem in
+            // client code. Possibly because the binaries were built
+            // incorrectly, but possibly because the library was loaded with
+            // dlopen.
+            //
             // Redo the search comparing type_info's using strcmp
             info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
             info.number_of_dst_type = 1;
@@ -672,10 +652,6 @@
         if (info.path_dst_ptr_to_static_ptr == unknown &&
             info.path_dynamic_ptr_to_static_ptr == unknown)
         {
-            syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
-                            " has hidden visibility.  They should all have public visibility.  "
-                            " %s, %s, %s.\n", static_type->name(), dynamic_type->name(),
-                    dst_type->name());
             // Redo the search comparing type_info's using strcmp
             info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
             dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -400,6 +400,10 @@
     add_definitions(-DLIBCXXABI_BAREMETAL)
 endif()
 
+if (LIBCXX_DYNAMIC_FALLBACK)
+    add_definitions(-D_LIBCXX_DYNAMIC_FALLBACK)
+endif()
+
 string(REPLACE ";" " " LIBCXXABI_CXX_FLAGS "${LIBCXXABI_CXX_FLAGS}")
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LIBCXXABI_CXX_FLAGS}")
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBCXXABI_C_FLAGS}")
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to