#include <folly/lang/Exception.h>
#include <atomic>
#include <cassert>
#include <cstring>
#include <folly/lang/New.h>
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
#include <cxxabi.h>
#if !defined(__FreeBSD__)
#include <unwind.h>
#endif
#endif
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
#if !defined(__FreeBSD__)
namespace __cxxabiv1 {
struct __cxa_eh_globals { … };
#if defined(__GLIBCXX__)
extern "C" [[gnu::const]] __cxa_eh_globals* __cxa_get_globals() noexcept;
#else
extern "C" __cxa_eh_globals* __cxa_get_globals();
#endif
}
#endif
#endif
namespace folly {
namespace detail {
unsigned int* uncaught_exceptions_ptr() noexcept { … }
}
}
#if defined(__GLIBCXX__)
#if defined(__ia64__) && defined(__hpux__)
typedef unsigned _Unwind_Ptr __attribute__((__mode__(__word__)));
#else
typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
#endif
namespace __cxxabiv1 {
static constexpr uint64_t __gxx_primary_exception_class =
0x474E5543432B2B00;
static constexpr uint64_t __gxx_dependent_exception_class =
0x474E5543432B2B01;
struct __cxa_exception {
std::type_info* exceptionType;
void(_GLIBCXX_CDTOR_CALLABI* exceptionDestructor)(void*);
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
__cxa_exception* nextException;
int handlerCount;
#ifdef __ARM_EABI_UNWINDER__
__cxa_exception* nextPropagatingException;
int propagationCount;
#else
int handlerSwitchValue;
const unsigned char* actionRecord;
const unsigned char* languageSpecificData;
_Unwind_Ptr catchTemp;
void* adjustedPtr;
#endif
_Unwind_Exception unwindHeader;
};
struct __cxa_refcounted_exception {
_Atomic_word referenceCount;
__cxa_exception exc;
};
}
#endif
#if defined(_LIBCPP_VERSION) && !defined(__FreeBSD__)
namespace std {
#if defined(_LIBCPP_FUNC_VIS)
#define FOLLY_DETAIL_EXN_FUNC_VIS …
#else
#define FOLLY_DETAIL_EXN_FUNC_VIS …
#endif
unexpected_handler;
FOLLY_DETAIL_EXN_FUNC_VIS unexpected_handler get_unexpected() _NOEXCEPT;
}
namespace __cxxabiv1 {
struct __folly_cxa_exception_sans_reserve { … };
struct __folly_cxa_exception_with_reserve { … };
static const uint64_t kOurExceptionClass = …;
class __folly_shim_type_info : public std::type_info { … };
}
abi;
#endif
#if defined(__FreeBSD__)
namespace __cxxabiv1 {
static const uint64_t kOurExceptionClass = 0x474E5543432B2B00;
class __folly_shim_type_info {
public:
virtual ~__folly_shim_type_info() = 0;
virtual bool __is_pointer_p() const = 0;
virtual bool __is_function_p() const = 0;
virtual bool __do_catch(
std::type_info const* thrown_type,
void** thrown_object,
unsigned outer) const = 0;
virtual bool __do_upcast(
std::type_info const* target, void** thrown_object) const = 0;
};
extern "C" void* __cxa_allocate_exception(size_t thrown_size) noexcept;
extern "C" void __cxa_free_exception(void* thrown_exception) noexcept;
}
namespace abi = __cxxabiv1;
#endif
#if defined(_WIN32)
#if defined(__clang__)
struct _s_ThrowInfo;
typedef const struct _s_ThrowInfo _ThrowInfo;
#endif
#include <ehdata.h>
extern "C" _CRTIMP2 void* __cdecl __AdjustPointer(void*, PMD const&);
#if !defined(__clang__)
template <class _E>
void* __GetExceptionInfo(_E);
#endif
#endif
namespace folly {
namespace detail {
namespace {
template <typename F>
class scope_guard_ { … };
}
std::atomic<int> exception_ptr_access_rt_cache_{ … };
bool exception_ptr_access_rt_() noexcept { … }
std::type_info const* exception_ptr_exception_typeid(
std::exception const& ex) noexcept { … }
#if defined(__GLIBCXX__)
bool exception_ptr_access_rt_v_() noexcept {
static_assert(exception_ptr_access_ct, "mismatch");
return true;
}
template <typename F>
static decltype(auto) cxxabi_with_cxa_exception(void* object, F f) {
using cxa_exception = abi::__cxa_exception;
auto exception = object ? static_cast<cxa_exception*>(object) - 1 : nullptr;
return f(exception);
}
std::type_info const* exception_ptr_get_type_(
std::exception_ptr const& ptr) noexcept {
if (!ptr) {
return nullptr;
}
auto object = reinterpret_cast<void* const&>(ptr);
auto exception = static_cast<abi::__cxa_exception*>(object) - 1;
return exception->exceptionType;
}
void* exception_ptr_get_object_(
std::exception_ptr const& ptr,
std::type_info const* const target) noexcept {
if (!ptr) {
return nullptr;
}
auto object = reinterpret_cast<void* const&>(ptr);
auto type = exception_ptr_get_type_(ptr);
return !target || target->__do_catch(type, &object, 1) ? object : nullptr;
}
#endif
#if defined(_LIBCPP_VERSION) && !defined(__FreeBSD__)
bool exception_ptr_access_rt_v_() noexcept { … }
static void* cxxabi_get_object(std::exception_ptr const& ptr) noexcept { … }
static bool cxxabi_cxa_exception_sans_reserve() noexcept { … }
template <typename F>
static decltype(auto) cxxabi_with_cxa_exception(void* object, F f) { … }
std::type_info const* exception_ptr_get_type_(
std::exception_ptr const& ptr) noexcept { … }
#if defined(__clang__)
__attribute__((no_sanitize("undefined")))
#endif
void* exception_ptr_get_object_(
std::exception_ptr const& ptr,
std::type_info const* const target) noexcept { … }
#endif
#if defined(__FreeBSD__)
bool exception_ptr_access_rt_v_() noexcept {
static_assert(exception_ptr_access_ct, "mismatch");
return true;
}
template <typename F>
static decltype(auto) cxxabi_with_cxa_exception(void* object, F f) {
using cxa_exception = abi::__cxa_exception;
auto exception = object ? static_cast<cxa_exception*>(object) - 1 : nullptr;
return f(exception);
}
std::type_info const* exception_ptr_get_type_(
std::exception_ptr const& ptr) noexcept {
if (!ptr) {
return nullptr;
}
auto object = reinterpret_cast<void* const&>(ptr);
auto exception = static_cast<abi::__cxa_exception*>(object) - 1;
return exception->exceptionType;
}
void* exception_ptr_get_object_(
std::exception_ptr const& ptr,
std::type_info const* const target) noexcept {
if (!ptr) {
return nullptr;
}
auto object = reinterpret_cast<void* const&>(ptr);
auto type = exception_ptr_get_type(ptr);
auto starget = reinterpret_cast<abi::__folly_shim_type_info const*>(target);
return !target || starget->__do_catch(type, &object, 1) ? object : nullptr;
}
#endif
#if defined(_WIN32)
template <typename T>
static T* win32_decode_pointer(T* ptr) {
return static_cast<T*>(
DecodePointer(const_cast<void*>(static_cast<void const*>(ptr))));
}
static EHExceptionRecord* win32_get_record(
std::exception_ptr const& ptr) noexcept {
return reinterpret_cast<std::shared_ptr<EHExceptionRecord> const&>(ptr).get();
}
static bool win32_eptr_throw_info_ptr_is_encoded() {
static std::atomic<int> cache{0};
if (auto value = cache.load(std::memory_order_relaxed)) {
return value > 0;
}
#if defined(__clang__)
auto info = std::__GetExceptionInfo(0);
#else
auto info = __GetExceptionInfo(0);
#endif
auto ptr = std::make_exception_ptr(0);
auto rec = win32_get_record(ptr);
int value = 0;
if (info == rec->params.pThrowInfo) {
value = -1;
}
if (info == win32_decode_pointer(rec->params.pThrowInfo)) {
value = +1;
}
assert(value);
cache.store(value, std::memory_order_relaxed);
return value > 0;
}
static ThrowInfo* win32_throw_info(EHExceptionRecord* rec) {
auto encoded = win32_eptr_throw_info_ptr_is_encoded();
auto info = rec->params.pThrowInfo;
return encoded ? win32_decode_pointer(info) : info;
}
static std::uintptr_t win32_throw_image_base(EHExceptionRecord* rec) {
#if _EH_RELATIVE_TYPEINFO
return reinterpret_cast<std::uintptr_t>(rec->params.pThrowImageBase);
#else
(void)rec;
return 0;
#endif
}
bool exception_ptr_access_rt_v_() noexcept {
static_assert(exception_ptr_access_ct, "mismatch");
return true;
}
std::type_info const* exception_ptr_get_type_(
std::exception_ptr const& ptr) noexcept {
auto rec = win32_get_record(ptr);
if (!rec) {
return nullptr;
}
auto base = win32_throw_image_base(rec);
auto info = win32_throw_info(rec);
auto cta_ = base + info->pCatchableTypeArray;
auto cta = reinterpret_cast<CatchableTypeArray*>(cta_);
auto ct_ = base + cta->arrayOfCatchableTypes[0];
auto ct = reinterpret_cast<CatchableType*>(ct_);
auto td_ = base + ct->pType;
auto td = reinterpret_cast<TypeDescriptor*>(td_);
return reinterpret_cast<std::type_info*>(td);
}
void* exception_ptr_get_object_(
std::exception_ptr const& ptr,
std::type_info const* const target) noexcept {
auto rec = win32_get_record(ptr);
if (!rec) {
return nullptr;
}
auto object = rec->params.pExceptionObject;
if (!target) {
return object;
}
auto base = win32_throw_image_base(rec);
auto info = win32_throw_info(rec);
auto cta_ = base + info->pCatchableTypeArray;
auto cta = reinterpret_cast<CatchableTypeArray*>(cta_);
for (int i = 0; i < cta->nCatchableTypes; i++) {
auto ct_ = base + cta->arrayOfCatchableTypes[i];
auto ct = reinterpret_cast<CatchableType*>(ct_);
auto td_ = base + ct->pType;
auto td = reinterpret_cast<TypeDescriptor*>(td_);
if (*target == *reinterpret_cast<std::type_info*>(td)) {
return __AdjustPointer(object, ct->thisDisplacement);
}
}
return nullptr;
}
#endif
}
namespace detail {
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
[[gnu::const]] abi::__cxa_eh_globals& cxa_get_globals() noexcept { … }
#endif
}
std::exception_ptr current_exception() noexcept { … }
namespace detail {
template <typename Try>
std::exception_ptr catch_current_exception_(Try&& t) noexcept { … }
#if defined(__GLIBCXX__)
std::exception_ptr make_exception_ptr_with_(
make_exception_ptr_with_arg_ const& arg, void* func) noexcept {
auto type = const_cast<std::type_info*>(arg.type);
void* object = abi::__cxa_allocate_exception(arg.size);
(void)abi::__cxa_init_primary_exception(object, type, arg.dtor);
auto exception = static_cast<abi::__cxa_refcounted_exception*>(object) - 1;
exception->referenceCount = 1;
return catch_current_exception_([&] {
scope_guard_ rollback{std::bind(abi::__cxa_free_exception, object)};
arg.ctor(object, func);
rollback.dismiss();
return reinterpret_cast<std::exception_ptr&&>(object);
});
}
#elif defined(_LIBCPP_VERSION)
[[maybe_unused]] static void exception_cleanup_(
_Unwind_Reason_Code reason, _Unwind_Exception* uwexception) { … }
std::exception_ptr make_exception_ptr_with_(
make_exception_ptr_with_arg_ const& arg, void* func) noexcept { … }
#else
std::exception_ptr make_exception_ptr_with_(
make_exception_ptr_with_arg_ const&, void*) noexcept {
return std::exception_ptr();
}
#endif
}
struct exception_shared_string::state { … };
exception_shared_string::exception_shared_string(
std::size_t const len, format_sig_& ffun, void* const fobj)
: … { … }
exception_shared_string::exception_shared_string(
literal_state_base const& base) noexcept
: … { … }
exception_shared_string::exception_shared_string(char const* const str)
: … { … }
exception_shared_string::exception_shared_string(
char const* const str, std::size_t const len)
: … { … }
exception_shared_string::exception_shared_string(
exception_shared_string const& that) noexcept
: … { … }
exception_shared_string::~exception_shared_string() { … }
char const* exception_shared_string::what() const noexcept { … }
}