[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/exception

The 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:
Stephan T. Lavavej 2026-07-10 11:26:24 -07:00 committed by GitHub
parent 188b9a3bfb
commit 9e13720eb8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 436 additions and 65 deletions

View file

@ -98,7 +98,7 @@ E: lebrungrandt@ornl.gov
D: Implementation of mdspan. D: Implementation of mdspan.
N: Microsoft Corporation 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. N: Bruce Mitchener, Jr.
E: bruce.mitchener@gmail.com E: bruce.mitchener@gmail.com

View file

@ -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_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. ``_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 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, ``_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. 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 Build System Changes
-------------------- --------------------

View file

@ -62,8 +62,6 @@ _LIBCPP_OVERRIDABLE_FUNC_VIS __cxa_exception* __cxa_init_primary_exception(
_LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD
_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
#ifndef _LIBCPP_ABI_MICROSOFT
inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT; inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT;
class _LIBCPP_EXPORTED_FROM_ABI exception_ptr { class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
@ -74,6 +72,8 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
template <class _Ep> template <class _Ep>
friend _LIBCPP_HIDE_FROM_ABI exception_ptr __make_exception_ptr_explicit(_Ep&) _NOEXCEPT; 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: public:
// exception_ptr is basically a COW string so it is trivially relocatable. // exception_ptr is basically a COW string so it is trivially relocatable.
using __trivially_relocatable _LIBCPP_NODEBUG = exception_ptr; 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_); std::swap(__x.__ptr_, __y.__ptr_);
} }
#ifndef _LIBCPP_ABI_MICROSOFT
# if _LIBCPP_HAS_EXCEPTIONS # if _LIBCPP_HAS_EXCEPTIONS
# if _LIBCPP_HAS_RTTI && _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION # if _LIBCPP_HAS_RTTI && _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
template <class _Ep> template <class _Ep>
@ -180,34 +182,7 @@ _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep) _NOEXCEPT {
#else // defined(_LIBCPP_ABI_MICROSOFT) #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 __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 // This is a built-in template function which automagically extracts the required
// information. // information.

View file

@ -7,62 +7,452 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include <exception> _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmultichar")
#include <stdio.h>
#include <stdlib.h>
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCreate(void*); #include <__exception/exception_ptr.h>
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrDestroy(void*); #include <__memory/shared_count.h>
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCopy(void*, const void*); #include <cstdlib>
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrAssign(void*, const void*); #include <cstring>
_LIBCPP_CRT_FUNC bool __cdecl __ExceptionPtrCompare(const void*, const void*);
_LIBCPP_CRT_FUNC bool __cdecl __ExceptionPtrToBool(const void*); #include <Unknwn.h>
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrSwap(void*, void*); #include <Windows.h>
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCurrentException(void*); struct _ThrowInfo;
[[noreturn]] _LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrRethrow(const void*); #include <eh.h>
_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCopyException(void*, const void*, const void*); #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 { namespace std {
exception_ptr::exception_ptr() noexcept { __ExceptionPtrCreate(this); } exception_ptr::~exception_ptr() noexcept {
exception_ptr::exception_ptr(nullptr_t) noexcept { __ExceptionPtrCreate(this); } 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 { 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; return *this;
} }
exception_ptr& exception_ptr::operator=(nullptr_t) noexcept { exception_ptr exception_ptr::__from_native_exception_pointer(void* __p) noexcept {
exception_ptr dummy; exception_ptr __ret;
__ExceptionPtrAssign(this, &dummy); __ret.__ptr_ = __p;
return *this; 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 __copy_exception_ptr(void* __except, const void* __ptr) {
exception_ptr __ret = nullptr; exception_ptr __ret = nullptr;
if (__ptr) if (!__ptr)
__ExceptionPtrCopyException(&__ret, __except, __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; return __ret;
} }
exception_ptr current_exception() noexcept { exception_ptr current_exception() noexcept {
exception_ptr __ret; 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; 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()) {} nested_exception::nested_exception() noexcept : __ptr_(current_exception()) {}