[libc++] Add MSVC's implementation of exception_ptr for Windows (#94977)
Microsoft is happy to contribute our implementation of exception_ptr for Windows, under the Apache License v2.0 with LLVM Exception that our STLs share. * excptptr.cpp, copied verbatim as:e36ee6c2b9/stl/src/excptptr.cpp* <exception>, copied verbatim as:e36ee6c2b9/stl/inc/exceptionThe implementation was integrated into libc++: * Deleted STL copy of <exception>. All standard exception classes are already provided by libc++'s standard headers. * Replaced MSVC STL naming conventions and macros (_STD, _CRTIMP2_PURE, _Ref_count_base, _Ptr_base, _EXCEPTION_RECORD, etc.) with standard libc++ style and identifiers (_LIBCPP_EXPORTED_FROM_ABI, __double_leading_underscore variable/function names). * Replaced internal MSVC CRT headers (<trnsctrl.h>, <internal_shared.h>, <xcall_once.h>) with portable standard C++ constructs (e.g., standard C++ function-local static initialization for immortal static exception objects) and inline pointer-to-member invocation helpers. * Removed all exported __ExceptionPtr... C functions. These symbols were originally present in Microsoft's CRT DLL exports solely to support inline methods in MSVC STL's <exception> header. * Moved all SEH/EH exception record definitions, SEH copying helpers (__populate_cpp_exception_record, __copy_exception_object), and reference-counted control blocks (__exception_ptr_static and __exception_ptr_normal) directly into exception_pointer_msvc.ipp. * Use reference-counted control block representation on Windows which removed the platform #ifdef _LIBCPP_ABI_MICROSOFT bifurcation for class exception_ptr in exception_ptr.h. std::exception_ptr now uses the same layout across all operating systems. Co-authored-by: Petr Hosek <phosek@google.com>
This commit is contained in:
parent
188b9a3bfb
commit
9e13720eb8
4 changed files with 436 additions and 65 deletions
|
|
@ -98,7 +98,7 @@ E: lebrungrandt@ornl.gov
|
|||
D: Implementation of mdspan.
|
||||
|
||||
N: Microsoft Corporation
|
||||
D: Contributed floating-point to_chars.
|
||||
D: Contributed floating-point to_chars and an implementation of exception_ptr for Windows.
|
||||
|
||||
N: Bruce Mitchener, Jr.
|
||||
E: bruce.mitchener@gmail.com
|
||||
|
|
|
|||
|
|
@ -128,6 +128,9 @@ Potentially breaking changes
|
|||
``_LIBCPP_ABI_NO_ITERATOR_BASES``. If you are using this flag and care about ABI stability, you should set
|
||||
``_LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER`` as well.
|
||||
|
||||
- ``std::exception_ptr`` on Windows no longer relies on STL and is now implemented entirely within libc++.
|
||||
The implementation was donated by Microsoft and has been refactored to follow libc++ standards and conventions.
|
||||
|
||||
Announcements About Future Releases
|
||||
-----------------------------------
|
||||
|
||||
|
|
@ -154,5 +157,8 @@ ABI Affecting Changes
|
|||
``_LIBCPP_DEPRECATED_ABI_BITSET_CONST_SUBSCRIPT_RETURN_REF``. Please inform the libc++ team if you need this flag,
|
||||
since it will be removed in LLVM 24 if there is no evidence that it's required.
|
||||
|
||||
- ``std::exception_ptr`` now uses the same layout on Windows as on other platforms, changing the size from two to one
|
||||
pointer.
|
||||
|
||||
Build System Changes
|
||||
--------------------
|
||||
|
|
|
|||
|
|
@ -62,8 +62,6 @@ _LIBCPP_OVERRIDABLE_FUNC_VIS __cxa_exception* __cxa_init_primary_exception(
|
|||
_LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD
|
||||
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
|
||||
|
||||
#ifndef _LIBCPP_ABI_MICROSOFT
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT;
|
||||
|
||||
class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
|
||||
|
|
@ -74,6 +72,8 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
|
|||
template <class _Ep>
|
||||
friend _LIBCPP_HIDE_FROM_ABI exception_ptr __make_exception_ptr_explicit(_Ep&) _NOEXCEPT;
|
||||
|
||||
friend _LIBCPP_EXPORTED_FROM_ABI exception_ptr __copy_exception_ptr(void*, const void*);
|
||||
|
||||
public:
|
||||
// exception_ptr is basically a COW string so it is trivially relocatable.
|
||||
using __trivially_relocatable _LIBCPP_NODEBUG = exception_ptr;
|
||||
|
|
@ -113,6 +113,8 @@ inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _
|
|||
std::swap(__x.__ptr_, __y.__ptr_);
|
||||
}
|
||||
|
||||
#ifndef _LIBCPP_ABI_MICROSOFT
|
||||
|
||||
# if _LIBCPP_HAS_EXCEPTIONS
|
||||
# if _LIBCPP_HAS_RTTI && _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
|
||||
template <class _Ep>
|
||||
|
|
@ -180,34 +182,7 @@ _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep) _NOEXCEPT {
|
|||
|
||||
#else // defined(_LIBCPP_ABI_MICROSOFT)
|
||||
|
||||
class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
|
||||
_LIBCPP_DIAGNOSTIC_PUSH
|
||||
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-private-field")
|
||||
void* __ptr1_;
|
||||
void* __ptr2_;
|
||||
_LIBCPP_DIAGNOSTIC_POP
|
||||
|
||||
public:
|
||||
exception_ptr() _NOEXCEPT;
|
||||
exception_ptr(nullptr_t) _NOEXCEPT;
|
||||
exception_ptr(const exception_ptr& __other) _NOEXCEPT;
|
||||
exception_ptr& operator=(const exception_ptr& __other) _NOEXCEPT;
|
||||
exception_ptr& operator=(nullptr_t) _NOEXCEPT;
|
||||
~exception_ptr() _NOEXCEPT;
|
||||
explicit operator bool() const _NOEXCEPT;
|
||||
};
|
||||
|
||||
_LIBCPP_EXPORTED_FROM_ABI bool operator==(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT;
|
||||
|
||||
inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT {
|
||||
return !(__x == __y);
|
||||
}
|
||||
|
||||
_LIBCPP_EXPORTED_FROM_ABI void swap(exception_ptr&, exception_ptr&) _NOEXCEPT;
|
||||
|
||||
_LIBCPP_EXPORTED_FROM_ABI exception_ptr __copy_exception_ptr(void* __except, const void* __ptr);
|
||||
_LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT;
|
||||
[[__noreturn__]] _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
|
||||
|
||||
// This is a built-in template function which automagically extracts the required
|
||||
// information.
|
||||
|
|
|
|||
|
|
@ -7,62 +7,452 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <exception>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmultichar")
|
||||
|
||||
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCreate(void*);
|
||||
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrDestroy(void*);
|
||||
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCopy(void*, const void*);
|
||||
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrAssign(void*, const void*);
|
||||
_LIBCPP_CRT_FUNC bool __cdecl __ExceptionPtrCompare(const void*, const void*);
|
||||
_LIBCPP_CRT_FUNC bool __cdecl __ExceptionPtrToBool(const void*);
|
||||
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrSwap(void*, void*);
|
||||
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCurrentException(void*);
|
||||
[[noreturn]] _LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrRethrow(const void*);
|
||||
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCopyException(void*, const void*, const void*);
|
||||
#include <__exception/exception_ptr.h>
|
||||
#include <__memory/shared_count.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include <Unknwn.h>
|
||||
#include <Windows.h>
|
||||
struct _ThrowInfo;
|
||||
#include <eh.h>
|
||||
#include <ehdata.h>
|
||||
#include <malloc.h> // alloca
|
||||
|
||||
// Pre-V4 managed exception code
|
||||
#define MANAGED_EXCEPTION_CODE 0XE0434F4D
|
||||
|
||||
// V4 and later managed exception code
|
||||
#define MANAGED_EXCEPTION_CODE_V4 0XE0434352
|
||||
|
||||
extern "C" _LIBCPP_CRT_FUNC void* __cdecl __AdjustPointer(void*, const PMD&);
|
||||
extern "C" _LIBCPP_CRT_FUNC void** __cdecl __current_exception();
|
||||
|
||||
namespace {
|
||||
|
||||
typedef void(__stdcall* __prepare_for_throw_t)(void*);
|
||||
|
||||
struct __winrt_exception_info {
|
||||
void* __description;
|
||||
void* __restricted_error_string;
|
||||
void* __restricted_error_reference;
|
||||
void* __capability_sid;
|
||||
long __hr;
|
||||
void* __restricted_info;
|
||||
ThrowInfo* __throw_info;
|
||||
unsigned int __size;
|
||||
__prepare_for_throw_t __prepare_throw;
|
||||
};
|
||||
|
||||
inline EHExceptionRecord* __get_current_exception() noexcept {
|
||||
return *reinterpret_cast<EHExceptionRecord**>(__current_exception());
|
||||
}
|
||||
|
||||
inline void __call_member_function_0(void* __this, void* __mfn) {
|
||||
auto __fn = reinterpret_cast<void(__thiscall*)(void*)>(__mfn);
|
||||
__fn(__this);
|
||||
}
|
||||
|
||||
inline void __call_member_function_1(void* __this, void* __mfn, void* __arg) {
|
||||
auto __fn = reinterpret_cast<void(__thiscall*)(void*, void*)>(__mfn);
|
||||
__fn(__this, __arg);
|
||||
}
|
||||
|
||||
inline void __call_member_function_2(void* __this, void* __mfn, void* __arg1, int __arg2) {
|
||||
auto __fn = reinterpret_cast<void(__thiscall*)(void*, void*, int)>(__mfn);
|
||||
__fn(__this, __arg1, __arg2);
|
||||
}
|
||||
|
||||
void __populate_cpp_exception_record(
|
||||
_EXCEPTION_RECORD& __record, const void* const __except_obj, ThrowInfo* __throw_info) noexcept {
|
||||
__record.ExceptionCode = EH_EXCEPTION_NUMBER;
|
||||
__record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||||
__record.ExceptionRecord = nullptr; // No SEH to chain.
|
||||
__record.ExceptionAddress = nullptr; // Address of exception. This will be overwritten by OS.
|
||||
__record.NumberParameters = EH_EXCEPTION_PARAMETERS;
|
||||
__record.ExceptionInformation[0] = EH_MAGIC_NUMBER1;
|
||||
__record.ExceptionInformation[1] = reinterpret_cast<ULONG_PTR>(__except_obj);
|
||||
|
||||
if (__throw_info && (__throw_info->attributes & TI_IsWinRT)) {
|
||||
// The pointer to the ExceptionInfo structure is stored sizeof(void*) in front of each WinRT Exception Info.
|
||||
const auto __wei = (*static_cast<__winrt_exception_info** const*>(const_cast<void*>(__except_obj)))[-1];
|
||||
__throw_info = __wei->__throw_info;
|
||||
}
|
||||
|
||||
__record.ExceptionInformation[2] = reinterpret_cast<ULONG_PTR>(__throw_info);
|
||||
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
void* __throw_image_base =
|
||||
__throw_info ? RtlPcToFileHeader(const_cast<void*>(static_cast<const void*>(__throw_info)), &__throw_image_base)
|
||||
: nullptr;
|
||||
__record.ExceptionInformation[3] = reinterpret_cast<ULONG_PTR>(__throw_image_base);
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
|
||||
// If the throw info indicates this throw is from a pure region, set the magic number to the Pure one, so only a
|
||||
// pure-region catch will see it.
|
||||
//
|
||||
// Also use the Pure magic number on 64-bit platforms if we were unable to determine an image base, since that was the
|
||||
// old way to determine a pure throw, before the TI_IsPure bit was added to the FuncInfo attributes field.
|
||||
if (__throw_info && ((__throw_info->attributes & TI_IsPure)
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
|| !__throw_image_base
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
))
|
||||
__record.ExceptionInformation[0] = EH_PURE_MAGIC_NUMBER1;
|
||||
}
|
||||
|
||||
void __copy_exception_record(_EXCEPTION_RECORD& __dest, const _EXCEPTION_RECORD& __src) noexcept {
|
||||
__dest.ExceptionCode = __src.ExceptionCode;
|
||||
// We force EXCEPTION_NONCONTINUABLE because rethrow_exception is [[noreturn]].
|
||||
__dest.ExceptionFlags = __src.ExceptionFlags | EXCEPTION_NONCONTINUABLE;
|
||||
__dest.ExceptionRecord = nullptr; // We don't chain SEH exceptions.
|
||||
__dest.ExceptionAddress = nullptr; // Useless field to copy. It will be overwritten by RaiseException().
|
||||
const auto __parameters = __src.NumberParameters;
|
||||
__dest.NumberParameters = __parameters;
|
||||
|
||||
// Copy the number of parameters in use.
|
||||
constexpr auto __max_parameters = static_cast<DWORD>(EXCEPTION_MAXIMUM_PARAMETERS);
|
||||
const auto __in_use = (__parameters < __max_parameters) ? __parameters : __max_parameters;
|
||||
std::memcpy(__dest.ExceptionInformation, __src.ExceptionInformation, __in_use * sizeof(ULONG_PTR));
|
||||
std::memset(&__dest.ExceptionInformation[__in_use], 0, (__max_parameters - __in_use) * sizeof(ULONG_PTR));
|
||||
}
|
||||
|
||||
void __copy_exception_object(void* __dest, const void* __src, const CatchableType* const __type
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
,
|
||||
uintptr_t __throw_image_base
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
) {
|
||||
// Copy an object of type denoted by *_PType from __src to __dDest; throws whatever the copy ctor of the type denoted
|
||||
// by *_PType throws.
|
||||
if ((__type->properties & CT_IsSimpleType) || __type->copyFunction == 0) {
|
||||
std::memcpy(__dest, __src, __type->sizeOrOffset);
|
||||
|
||||
if (__type->properties & CT_IsWinRTHandle) {
|
||||
const auto __unknown = *static_cast<IUnknown* const*>(const_cast<void*>(__src));
|
||||
if (__unknown)
|
||||
__unknown->AddRef();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
const auto __copy_func = reinterpret_cast<void*>(__throw_image_base + __type->copyFunction);
|
||||
#else // _EH_RELATIVE_TYPEINFO
|
||||
const auto __copy_func = __type->copyFunction;
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
|
||||
const auto __adjusted = __AdjustPointer(const_cast<void*>(__src), __type->thisDisplacement);
|
||||
if (__type->properties & CT_HasVirtualBase)
|
||||
__call_member_function_2(__dest, __copy_func, __adjusted, 1);
|
||||
else
|
||||
__call_member_function_1(__dest, __copy_func, __adjusted);
|
||||
}
|
||||
|
||||
struct __exception_ptr_storage : public std::__shared_count {
|
||||
_EXCEPTION_RECORD __record_;
|
||||
explicit __exception_ptr_storage(long __refs = 0) noexcept : std::__shared_count(__refs) {}
|
||||
};
|
||||
|
||||
template <class _StaticEx>
|
||||
struct __exception_ptr_static final : public __exception_ptr_storage {
|
||||
_StaticEx __ex_;
|
||||
|
||||
__exception_ptr_static() noexcept : __exception_ptr_storage(0) {
|
||||
__populate_cpp_exception_record(__record_, &__ex_, static_cast<ThrowInfo*>(__GetExceptionInfo(__ex_)));
|
||||
}
|
||||
|
||||
void __on_zero_shared() noexcept override {}
|
||||
|
||||
static __exception_ptr_storage* __get() noexcept {
|
||||
struct __container {
|
||||
union {
|
||||
__exception_ptr_static __instance_;
|
||||
};
|
||||
__container() noexcept : __instance_() {}
|
||||
~__container() {}
|
||||
};
|
||||
static __container __storage;
|
||||
return &__storage.__instance_;
|
||||
}
|
||||
};
|
||||
|
||||
struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) __exception_ptr_normal final : public __exception_ptr_storage {
|
||||
explicit __exception_ptr_normal(const _EXCEPTION_RECORD& __record) noexcept : __exception_ptr_storage(0) {
|
||||
__copy_exception_record(__record_, __record);
|
||||
}
|
||||
|
||||
void __on_zero_shared() noexcept override {
|
||||
const auto& __cpp_eh_record = reinterpret_cast<EHExceptionRecord&>(__record_);
|
||||
if (PER_IS_MSVC_PURE_OR_NATIVE_EH(&__cpp_eh_record)) {
|
||||
const auto* __throw_info = __cpp_eh_record.params.pThrowInfo;
|
||||
if (__throw_info && __cpp_eh_record.params.pExceptionObject) {
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
const auto __throw_image_base = reinterpret_cast<uintptr_t>(__cpp_eh_record.params.pThrowImageBase);
|
||||
const auto* __catchable_type_array = reinterpret_cast<const CatchableTypeArray*>(
|
||||
static_cast<uintptr_t>(__throw_info->pCatchableTypeArray) + __throw_image_base);
|
||||
const auto* __type = reinterpret_cast<CatchableType*>(
|
||||
static_cast<uintptr_t>(__catchable_type_array->arrayOfCatchableTypes[0]) + __throw_image_base);
|
||||
#else // _EH_RELATIVE_TYPEINFO
|
||||
const auto* __type = __throw_info->pCatchableTypeArray->arrayOfCatchableTypes[0];
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
if (__throw_info->pmfnUnwind) {
|
||||
// The exception was a user defined type with a nontrivial destructor, call it.
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
__call_member_function_0(__cpp_eh_record.params.pExceptionObject,
|
||||
reinterpret_cast<void*>(__throw_info->pmfnUnwind + __throw_image_base));
|
||||
#else // _EH_RELATIVE_TYPEINFO
|
||||
__call_member_function_0(__cpp_eh_record.params.pExceptionObject, __throw_info->pmfnUnwind);
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
} else if (__type->properties & CT_IsWinRTHandle) {
|
||||
const auto* __unknown = *static_cast<IUnknown* const*>(__cpp_eh_record.params.pExceptionObject);
|
||||
if (__unknown)
|
||||
const_cast<IUnknown*>(__unknown)->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::free(this);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(__exception_ptr_normal) % __STDCPP_DEFAULT_NEW_ALIGNMENT__ == 0,
|
||||
"Exception in exception_ptr would be constructed with the wrong alignment");
|
||||
|
||||
void __assign_seh_exception_ptr_from_record(
|
||||
void*& __dest, const _EXCEPTION_RECORD& __record, void* const __rx_raw) noexcept {
|
||||
if (!__rx_raw) {
|
||||
__dest = __exception_ptr_static<std::bad_alloc>::__get();
|
||||
return;
|
||||
}
|
||||
|
||||
__dest = ::new (__rx_raw) __exception_ptr_normal(__record);
|
||||
}
|
||||
|
||||
void __assign_cpp_exception_ptr_from_record(void*& __dest, const EHExceptionRecord& __record) noexcept {
|
||||
// Construct a reference count control block for the C++ exception recorded by __record, and bind it to __dest.
|
||||
//
|
||||
// * If allocating memory for the reference count control block fails, sets __dest to bad_alloc.
|
||||
// * If copying the exception object referred to __record throws, constructs a reference count control block for that
|
||||
// exception instead.
|
||||
// * If copying the exception object thrown by copying the original exception object throws, sets __dest to
|
||||
// bad_exception.
|
||||
const auto* __throw_info = __record.params.pThrowInfo;
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
const auto __throw_image_base = reinterpret_cast<uintptr_t>(__record.params.pThrowImageBase);
|
||||
const auto* __catchable_type_array = reinterpret_cast<const CatchableTypeArray*>(
|
||||
static_cast<uintptr_t>(__throw_info->pCatchableTypeArray) + __throw_image_base);
|
||||
const auto* __type = reinterpret_cast<CatchableType*>(
|
||||
static_cast<uintptr_t>(__catchable_type_array->arrayOfCatchableTypes[0]) + __throw_image_base);
|
||||
#else // _EH_RELATIVE_TYPEINFO
|
||||
const auto* __type = __throw_info->pCatchableTypeArray->arrayOfCatchableTypes[0];
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
|
||||
const auto __except_obj_size = static_cast<size_t>(__type->sizeOrOffset);
|
||||
const auto __alloc_size = sizeof(__exception_ptr_normal) + __except_obj_size;
|
||||
auto* __rx_raw = std::malloc(__alloc_size);
|
||||
if (!__rx_raw) {
|
||||
__dest = __exception_ptr_static<std::bad_alloc>::__get();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
__copy_exception_object(static_cast<__exception_ptr_normal*>(__rx_raw) + 1,
|
||||
__record.params.pExceptionObject,
|
||||
__type
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
,
|
||||
__throw_image_base
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
);
|
||||
|
||||
const auto* __rx = ::new (__rx_raw) __exception_ptr_normal(reinterpret_cast<const _EXCEPTION_RECORD&>(__record));
|
||||
reinterpret_cast<EHExceptionRecord&>(const_cast<__exception_ptr_normal*>(__rx)->__record_).params.pExceptionObject =
|
||||
static_cast<__exception_ptr_normal*>(__rx_raw) + 1;
|
||||
__dest = const_cast<__exception_ptr_normal*>(__rx);
|
||||
} catch (...) { // Copying the exception object threw an exception.
|
||||
// Exception thrown by the original exception's copy ctor.
|
||||
const auto* __inner_record_ptr = __get_current_exception();
|
||||
if (!__inner_record_ptr) {
|
||||
std::free(__rx_raw);
|
||||
__dest = __exception_ptr_static<std::bad_exception>::__get();
|
||||
return;
|
||||
}
|
||||
const auto& __inner_record = *__inner_record_ptr;
|
||||
if (__inner_record.ExceptionCode == MANAGED_EXCEPTION_CODE ||
|
||||
__inner_record.ExceptionCode == MANAGED_EXCEPTION_CODE_V4) {
|
||||
// We don't support managed exceptions and don't want to say there's no active exception, so give up and say
|
||||
// bad_exception.
|
||||
std::free(__rx_raw);
|
||||
__dest = __exception_ptr_static<std::bad_exception>::__get();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PER_IS_MSVC_PURE_OR_NATIVE_EH(&__inner_record)) { // Catching a non-C++ exception depends on /EHa.
|
||||
__assign_seh_exception_ptr_from_record(
|
||||
__dest, reinterpret_cast<const _EXCEPTION_RECORD&>(__inner_record), __rx_raw);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* __inner_throw = __inner_record.params.pThrowInfo;
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
const auto __inner_throw_image_base = reinterpret_cast<uintptr_t>(__inner_record.params.pThrowImageBase);
|
||||
const auto* __inner_catchable_type_array = reinterpret_cast<const CatchableTypeArray*>(
|
||||
static_cast<uintptr_t>(__inner_throw->pCatchableTypeArray) + __inner_throw_image_base);
|
||||
const auto* __inner_type = reinterpret_cast<CatchableType*>(
|
||||
static_cast<uintptr_t>(__inner_catchable_type_array->arrayOfCatchableTypes[0]) + __inner_throw_image_base);
|
||||
#else // _EH_RELATIVE_TYPEINFO
|
||||
const auto* __inner_type = __inner_throw->pCatchableTypeArray->arrayOfCatchableTypes[0];
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
|
||||
const auto __inner_except_size = static_cast<size_t>(__inner_type->sizeOrOffset);
|
||||
const auto __inner_alloc_size = sizeof(__exception_ptr_normal) + __inner_except_size;
|
||||
if (__inner_alloc_size > __alloc_size) {
|
||||
std::free(__rx_raw);
|
||||
__rx_raw = std::malloc(__inner_alloc_size);
|
||||
if (!__rx_raw) {
|
||||
__dest = __exception_ptr_static<std::bad_alloc>::__get();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
__copy_exception_object(static_cast<__exception_ptr_normal*>(__rx_raw) + 1,
|
||||
__inner_record.params.pExceptionObject,
|
||||
__inner_type
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
,
|
||||
__inner_throw_image_base
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
);
|
||||
} catch (...) { // Copying the exception emitted while copying the original exception also threw, give up.
|
||||
std::free(__rx_raw);
|
||||
__dest = __exception_ptr_static<std::bad_exception>::__get();
|
||||
return;
|
||||
}
|
||||
|
||||
// This next block must be duplicated inside the catch (even though it looks identical to the block in the try) so
|
||||
// that __inner_record is held alive; exiting the catch will destroy it.
|
||||
const auto* __rx =
|
||||
::new (__rx_raw) __exception_ptr_normal(reinterpret_cast<const _EXCEPTION_RECORD&>(__inner_record));
|
||||
reinterpret_cast<EHExceptionRecord&>(const_cast<__exception_ptr_normal*>(__rx)->__record_).params.pExceptionObject =
|
||||
static_cast<__exception_ptr_normal*>(__rx_raw) + 1;
|
||||
__dest = const_cast<__exception_ptr_normal*>(__rx);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace std {
|
||||
|
||||
exception_ptr::exception_ptr() noexcept { __ExceptionPtrCreate(this); }
|
||||
exception_ptr::exception_ptr(nullptr_t) noexcept { __ExceptionPtrCreate(this); }
|
||||
exception_ptr::~exception_ptr() noexcept {
|
||||
if (__ptr_)
|
||||
static_cast<__shared_count*>(__ptr_)->__release_shared();
|
||||
}
|
||||
|
||||
exception_ptr::exception_ptr(const exception_ptr& __other) noexcept : __ptr_(__other.__ptr_) {
|
||||
if (__ptr_)
|
||||
static_cast<__shared_count*>(__ptr_)->__add_shared();
|
||||
}
|
||||
|
||||
exception_ptr::exception_ptr(const exception_ptr& __other) noexcept { __ExceptionPtrCopy(this, &__other); }
|
||||
exception_ptr& exception_ptr::operator=(const exception_ptr& __other) noexcept {
|
||||
__ExceptionPtrAssign(this, &__other);
|
||||
if (__ptr_ != __other.__ptr_) {
|
||||
if (__other.__ptr_)
|
||||
static_cast<__shared_count*>(__other.__ptr_)->__add_shared();
|
||||
if (__ptr_)
|
||||
static_cast<__shared_count*>(__ptr_)->__release_shared();
|
||||
__ptr_ = __other.__ptr_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
exception_ptr& exception_ptr::operator=(nullptr_t) noexcept {
|
||||
exception_ptr dummy;
|
||||
__ExceptionPtrAssign(this, &dummy);
|
||||
return *this;
|
||||
exception_ptr exception_ptr::__from_native_exception_pointer(void* __p) noexcept {
|
||||
exception_ptr __ret;
|
||||
__ret.__ptr_ = __p;
|
||||
if (__ret.__ptr_)
|
||||
static_cast<__shared_count*>(__ret.__ptr_)->__add_shared();
|
||||
return __ret;
|
||||
}
|
||||
|
||||
exception_ptr::~exception_ptr() noexcept { __ExceptionPtrDestroy(this); }
|
||||
|
||||
exception_ptr::operator bool() const noexcept { return __ExceptionPtrToBool(this); }
|
||||
|
||||
bool operator==(const exception_ptr& __x, const exception_ptr& __y) noexcept {
|
||||
return __ExceptionPtrCompare(&__x, &__y);
|
||||
}
|
||||
|
||||
void swap(exception_ptr& lhs, exception_ptr& rhs) noexcept { __ExceptionPtrSwap(&rhs, &lhs); }
|
||||
|
||||
exception_ptr __copy_exception_ptr(void* __except, const void* __ptr) {
|
||||
exception_ptr __ret = nullptr;
|
||||
if (__ptr)
|
||||
__ExceptionPtrCopyException(&__ret, __except, __ptr);
|
||||
if (!__ptr)
|
||||
return __ret;
|
||||
|
||||
_EXCEPTION_RECORD __record;
|
||||
__populate_cpp_exception_record(__record, __except, static_cast<ThrowInfo*>(const_cast<void*>(__ptr)));
|
||||
__assign_cpp_exception_ptr_from_record(__ret.__ptr_, reinterpret_cast<const EHExceptionRecord&>(__record));
|
||||
return __ret;
|
||||
}
|
||||
|
||||
exception_ptr current_exception() noexcept {
|
||||
exception_ptr __ret;
|
||||
__ExceptionPtrCurrentException(&__ret);
|
||||
const auto* __record = __get_current_exception();
|
||||
if (!__record || __record->ExceptionCode == MANAGED_EXCEPTION_CODE ||
|
||||
__record->ExceptionCode == MANAGED_EXCEPTION_CODE_V4)
|
||||
return __ret;
|
||||
|
||||
if (PER_IS_MSVC_PURE_OR_NATIVE_EH(__record))
|
||||
__assign_cpp_exception_ptr_from_record(__ret.__ptr_, *__record);
|
||||
else
|
||||
__assign_seh_exception_ptr_from_record(
|
||||
__ret.__ptr_, reinterpret_cast<const _EXCEPTION_RECORD&>(*__record), std::malloc(sizeof(__exception_ptr_normal)));
|
||||
return __ret;
|
||||
}
|
||||
|
||||
[[noreturn]] void rethrow_exception(exception_ptr p) { __ExceptionPtrRethrow(&p); }
|
||||
[[noreturn]] void rethrow_exception(exception_ptr __p) {
|
||||
if (!__p)
|
||||
throw bad_exception();
|
||||
|
||||
auto* __rep = static_cast<__exception_ptr_storage*>(__p.__ptr_);
|
||||
auto __record_copy = __rep->__record_;
|
||||
auto& __cpp_record = reinterpret_cast<EHExceptionRecord&>(__record_copy);
|
||||
if (PER_IS_MSVC_PURE_OR_NATIVE_EH(&__cpp_record)) {
|
||||
const auto* __throw_info = __cpp_record.params.pThrowInfo;
|
||||
if (!__cpp_record.params.pExceptionObject || !__throw_info || !__throw_info->pCatchableTypeArray)
|
||||
terminate();
|
||||
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
const auto __throw_image_base = reinterpret_cast<uintptr_t>(__cpp_record.params.pThrowImageBase);
|
||||
const auto* __catchable_type_array =
|
||||
reinterpret_cast<const CatchableTypeArray*>(__throw_image_base + __throw_info->pCatchableTypeArray);
|
||||
#else // _EH_RELATIVE_TYPEINFO
|
||||
const auto* __catchable_type_array = __throw_info->pCatchableTypeArray;
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
|
||||
if (__catchable_type_array->nCatchableTypes <= 0)
|
||||
terminate();
|
||||
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
const auto* __type = reinterpret_cast<CatchableType*>(
|
||||
static_cast<uintptr_t>(__catchable_type_array->arrayOfCatchableTypes[0]) + __throw_image_base);
|
||||
#else // _EH_RELATIVE_TYPEINFO
|
||||
const auto* __type = __throw_info->pCatchableTypeArray->arrayOfCatchableTypes[0];
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
|
||||
#pragma warning(suppress : 6255)
|
||||
void* __exception_buffer = alloca(__type->sizeOrOffset);
|
||||
__copy_exception_object(__exception_buffer, __cpp_record.params.pExceptionObject, __type
|
||||
#if _EH_RELATIVE_TYPEINFO
|
||||
,
|
||||
__throw_image_base
|
||||
#endif // _EH_RELATIVE_TYPEINFO
|
||||
);
|
||||
|
||||
__cpp_record.params.pExceptionObject = __exception_buffer;
|
||||
}
|
||||
|
||||
// Under MSVC C++ exception handling (/EHsc), C Win32 API functions like RaiseException
|
||||
// are assumed not to throw synchronous C++ exceptions. As a result, stack unwinding
|
||||
// initiated by RaiseException does not execute local destructors in this frame.
|
||||
// We must explicitly reset __p here so that the reference count on the stored
|
||||
// exception record is properly decremented before unwinding begins.
|
||||
__p = nullptr;
|
||||
RaiseException(__record_copy.ExceptionCode, __record_copy.ExceptionFlags, __record_copy.NumberParameters,
|
||||
__record_copy.ExceptionInformation);
|
||||
terminate();
|
||||
}
|
||||
|
||||
nested_exception::nested_exception() noexcept : __ptr_(current_exception()) {}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue