Commit 0fee9dfc authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

fix exception-ptr accessors for libc++ again

Summary:
Another approach to fixing the exception-ptr accessors for libc++.

This time, just define mimics of `__cxa_exception` both ways, and test to find out which way to cast.

Reviewed By: JunqiWang

Differential Revision: D28561635

fbshipit-source-id: d27430d8fe2d73205bf1a8c31321be4c76808df8
parent cc0eeb35
...@@ -247,6 +247,11 @@ check_cxx_source_compiles(" ...@@ -247,6 +247,11 @@ check_cxx_source_compiles("
FOLLY_STDLIB_LIBCPP FOLLY_STDLIB_LIBCPP
) )
if (APPLE)
list (APPEND CMAKE_REQUIRED_LIBRARIES c++abi)
list (APPEND FOLLY_LINK_LIBRARIES c++abi)
endif ()
if (FOLLY_STDLIB_LIBSTDCXX AND NOT FOLLY_STDLIB_LIBSTDCXX_GE_9) if (FOLLY_STDLIB_LIBSTDCXX AND NOT FOLLY_STDLIB_LIBSTDCXX_GE_9)
list (APPEND CMAKE_REQUIRED_LIBRARIES stdc++fs) list (APPEND CMAKE_REQUIRED_LIBRARIES stdc++fs)
list (APPEND FOLLY_LINK_LIBRARIES stdc++fs) list (APPEND FOLLY_LINK_LIBRARIES stdc++fs)
......
...@@ -51,7 +51,35 @@ ...@@ -51,7 +51,35 @@
namespace __cxxabiv1 { namespace __cxxabiv1 {
struct __folly_cxa_exception { // the definition until llvm v10.0.0-rc2
struct __folly_cxa_exception_sans_reserve {
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
size_t referenceCount;
#endif
std::type_info* exceptionType;
void (*exceptionDestructor)(void*);
void (*unexpectedHandler)();
std::terminate_handler terminateHandler;
__folly_cxa_exception_sans_reserve* nextException;
int handlerCount;
#if defined(_LIBCXXABI_ARM_EHABI)
__folly_cxa_exception_sans_reserve* nextPropagatingException;
int propagationCount;
#else
int handlerSwitchValue;
const unsigned char* actionRecord;
const unsigned char* languageSpecificData;
void* catchTemp;
void* adjustedPtr;
#endif
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
size_t referenceCount;
#endif
_Unwind_Exception unwindHeader;
};
// the definition since llvm v10.0.0-rc2
struct __folly_cxa_exception_with_reserve {
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI) #if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
void* reserve; void* reserve;
size_t referenceCount; size_t referenceCount;
...@@ -60,10 +88,10 @@ struct __folly_cxa_exception { ...@@ -60,10 +88,10 @@ struct __folly_cxa_exception {
void (*exceptionDestructor)(void*); void (*exceptionDestructor)(void*);
void (*unexpectedHandler)(); void (*unexpectedHandler)();
std::terminate_handler terminateHandler; std::terminate_handler terminateHandler;
__folly_cxa_exception* nextException; __folly_cxa_exception_with_reserve* nextException;
int handlerCount; int handlerCount;
#if defined(_LIBCXXABI_ARM_EHABI) #if defined(_LIBCXXABI_ARM_EHABI)
__folly_cxa_exception* nextPropagatingException; __folly_cxa_exception_with_reserve* nextPropagatingException;
int propagationCount; int propagationCount;
#else #else
int handlerSwitchValue; int handlerSwitchValue;
...@@ -170,12 +198,8 @@ static void* cxxabi_get_object(std::exception_ptr const& ptr) noexcept { ...@@ -170,12 +198,8 @@ static void* cxxabi_get_object(std::exception_ptr const& ptr) noexcept {
return reinterpret_cast<void* const&>(ptr); return reinterpret_cast<void* const&>(ptr);
} }
static std::intptr_t cxxabi_cxa_exception_fields_adjustment() noexcept { static bool cxxabi_cxa_exception_sans_reserve() noexcept {
#if defined(__LP64__) || defined(_WIN64) || !defined(_LIBCXXABI_ARM_EHABI) // detect and cache the layout of __cxa_exception in the loaded libc++abi
return 0;
#endif
// detect and cache whether this version of llvm has __cxa_exception with
// shifted fields
// //
// for 32-bit arm-ehabi llvm ... // for 32-bit arm-ehabi llvm ...
// //
...@@ -185,8 +209,7 @@ static std::intptr_t cxxabi_cxa_exception_fields_adjustment() noexcept { ...@@ -185,8 +209,7 @@ static std::intptr_t cxxabi_cxa_exception_fields_adjustment() noexcept {
// //
// before v10.0.0-rc2, __cxa_exception has 4b padding before the unwind field // before v10.0.0-rc2, __cxa_exception has 4b padding before the unwind field
// as of v10.0.0-rc2, __cxa_exception moves the 4b padding to the start in a // as of v10.0.0-rc2, __cxa_exception moves the 4b padding to the start in a
// field called reserve, but this field also exists as of this version in 64- // field called reserve
// bit llvm but not before
// //
// before 32-bit arm-ehabi llvm v10.0.0-rc2, the reserve field does not exist // before 32-bit arm-ehabi llvm v10.0.0-rc2, the reserve field does not exist
// in the struct explicitly but the refcount field is there instead due to // in the struct explicitly but the refcount field is there instead due to
...@@ -202,31 +225,35 @@ static std::intptr_t cxxabi_cxa_exception_fields_adjustment() noexcept { ...@@ -202,31 +225,35 @@ static std::intptr_t cxxabi_cxa_exception_fields_adjustment() noexcept {
// fields except for the unwind field are shifted up by 4b // fields except for the unwind field are shifted up by 4b
// //
// prefer optimistic concurrency over pessimistic concurrency // prefer optimistic concurrency over pessimistic concurrency
static std::atomic<std::ptrdiff_t> cache{0}; // encoded static std::atomic<int> cache{};
if (auto encoded = cache.load(std::memory_order_relaxed)) { if (auto value = cache.load(std::memory_order_relaxed)) {
return (encoded - 1) / 2; return value > 0;
} else {
auto object = abi::__cxa_allocate_exception(0);
abi::__cxa_increment_exception_refcount(object);
auto exception = static_cast<abi::__folly_cxa_exception*>(object) - 1;
std::ptrdiff_t shift = 0;
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
if (exception->referenceCount != 1) {
assert(exception->reserve = reinterpret_cast<void*>(1));
shift = -static_cast<std::ptrdiff_t>(sizeof(exception->reserve));
}
#endif
abi::__cxa_free_exception(object); // no need for decref
cache.store(shift * 2 + 1, std::memory_order_relaxed);
return shift;
} }
auto object = abi::__cxa_allocate_exception(0);
abi::__cxa_increment_exception_refcount(object);
auto exception =
static_cast<abi::__folly_cxa_exception_sans_reserve*>(object) - 1;
auto result = exception->referenceCount == 1;
assert(
result ||
(static_cast<abi::__folly_cxa_exception_with_reserve*>(object) - 1)
->referenceCount == 1);
abi::__cxa_free_exception(object); // no need for decref
cache.store(result ? 1 : -1, std::memory_order_relaxed);
return result;
} }
static abi::__folly_cxa_exception* cxxabi_cxa_exception_fields_adjusted( template <typename F>
abi::__folly_cxa_exception* exception) noexcept { static decltype(auto) cxxabi_with_cxa_exception(void* object, F f) {
auto shift = cxxabi_cxa_exception_fields_adjustment(); if (cxxabi_cxa_exception_sans_reserve()) {
return reinterpret_cast<abi::__folly_cxa_exception*>( using cxa_exception = abi::__folly_cxa_exception_sans_reserve;
reinterpret_cast<char*>(exception) + shift); auto exception = object ? static_cast<cxa_exception*>(object) - 1 : nullptr;
return f(exception);
} else {
using cxa_exception = abi::__folly_cxa_exception_with_reserve;
auto exception = object ? static_cast<cxa_exception*>(object) - 1 : nullptr;
return f(exception);
}
} }
std::type_info const* exception_ptr_get_type( std::type_info const* exception_ptr_get_type(
...@@ -235,9 +262,9 @@ std::type_info const* exception_ptr_get_type( ...@@ -235,9 +262,9 @@ std::type_info const* exception_ptr_get_type(
return nullptr; return nullptr;
} }
auto object = cxxabi_get_object(ptr); auto object = cxxabi_get_object(ptr);
auto exception = static_cast<abi::__folly_cxa_exception*>(object) - 1; return cxxabi_with_cxa_exception(object, [](auto exception) { //
auto adjusted_ = cxxabi_cxa_exception_fields_adjusted(exception); return exception->exceptionType;
return adjusted_->exceptionType; });
} }
void* exception_ptr_get_object( void* exception_ptr_get_object(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment