diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h --- a/libcxx/include/__exception/exception_ptr.h +++ b/libcxx/include/__exception/exception_ptr.h @@ -14,6 +14,8 @@ #include <__memory/addressof.h> #include #include +#include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -26,6 +28,18 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr { void* __ptr_; + template + static inline void __dest_thunk(void* __x) { + static_cast<_Ep*>(__x)->~_Ep(); + } + + static void* init_ex(size_t, std::type_info*, void (*)(void*)) _NOEXCEPT; + static void free_ex(void*) _NOEXCEPT; + static exception_ptr from_ex_ptr(void* __e) _NOEXCEPT; + + template + friend _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep) _NOEXCEPT; + public: _LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {} _LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {} @@ -51,11 +65,24 @@ template _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT { # ifndef _LIBCPP_HAS_NO_EXCEPTIONS +# if defined(LIBCXX_BUILDING_LIBCXXABI) + using _Ep2 = typename decay<_Ep>::type; + void* __ex = + exception_ptr::init_ex(sizeof(_Ep), const_cast(&typeid(_Ep)), exception_ptr::__dest_thunk<_Ep2>); + try { + ::new (__ex) _Ep2(__e); + return exception_ptr::from_ex_ptr(__ex); + } catch (...) { + exception_ptr::free_ex(__ex); + return current_exception(); + } +# else try { throw __e; } catch (...) { return current_exception(); } +# endif # else ((void)__e); std::abort(); diff --git a/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp b/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp --- a/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp +++ b/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp @@ -34,6 +34,24 @@ return *this; } +void *exception_ptr::init_ex(size_t size, type_info *tinfo, void (*dest)(void *)) noexcept { + void *__ex = __cxa_allocate_exception(size); + (void)__cxa_init_primary_exception(__ex, tinfo, dest); + return __ex; +} + +void exception_ptr::free_ex(void *thrown_object) noexcept { + __cxa_free_exception(thrown_object); +} + +exception_ptr exception_ptr::from_ex_ptr(void *__e) noexcept { + exception_ptr ptr; + ptr.__ptr_ = __e; + __cxa_increment_exception_refcount(ptr.__ptr_); + + return ptr; +} + nested_exception::nested_exception() noexcept : __ptr_(current_exception()) { diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h --- a/libcxxabi/include/cxxabi.h +++ b/libcxxabi/include/cxxabi.h @@ -36,6 +36,9 @@ // runtime routines use C calling conventions, but are in __cxxabiv1 namespace namespace __cxxabiv1 { + +struct __cxa_exception; + extern "C" { // 2.4.2 Allocating the Exception Object @@ -43,6 +46,9 @@ __cxa_allocate_exception(size_t thrown_size) throw(); extern _LIBCXXABI_FUNC_VIS void __cxa_free_exception(void *thrown_exception) throw(); +// This function is an llvm extension +extern _LIBCXXABI_FUNC_VIS __cxa_exception* +__cxa_init_primary_exception(void* object, std::type_info* tinfo, void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw(); // 2.4.3 Throwing the Exception Object extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void diff --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp --- a/libcxxabi/src/cxa_exception.cpp +++ b/libcxxabi/src/cxa_exception.cpp @@ -206,6 +206,19 @@ __aligned_free_with_fallback((void *)raw_buffer); } +__cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinfo, + void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(object); + exception_header->referenceCount = 0; + exception_header->unexpectedHandler = std::get_unexpected(); + exception_header->terminateHandler = std::get_terminate(); + exception_header->exceptionType = tinfo; + exception_header->exceptionDestructor = dest; + setOurExceptionClass(&exception_header->unwindHeader); + exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; + + return exception_header; +} // This function shall allocate a __cxa_dependent_exception and // return a pointer to it. (Really to the object, not past its' end). @@ -255,18 +268,11 @@ */ void __cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) { - __cxa_eh_globals *globals = __cxa_get_globals(); - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - - exception_header->unexpectedHandler = std::get_unexpected(); - exception_header->terminateHandler = std::get_terminate(); - exception_header->exceptionType = tinfo; - exception_header->exceptionDestructor = dest; - setOurExceptionClass(&exception_header->unwindHeader); - exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. + __cxa_eh_globals* globals = __cxa_get_globals(); globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local - exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; + __cxa_exception* exception_header = __cxa_init_primary_exception(thrown_object, tinfo, dest); + exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. #if __has_feature(address_sanitizer) // Inform the ASan runtime that now might be a good time to clean stuff up.