X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FExceptionWrapper-inl.h;h=790b24ca09bd39d95cc916c507b7b4a00c936df0;hp=287275aec9ed73ab53bfba9fffb8f80a42b34de7;hb=f19e2b86e49ad30f2279262a672be852283644d2;hpb=03c1142df9b0ddd450430b7aae70940c0d071ff6 diff --git a/folly/ExceptionWrapper-inl.h b/folly/ExceptionWrapper-inl.h index 287275ae..790b24ca 100644 --- a/folly/ExceptionWrapper-inl.h +++ b/folly/ExceptionWrapper-inl.h @@ -18,6 +18,8 @@ * Author: Eric Niebler */ +#include + namespace folly { template @@ -67,9 +69,9 @@ inline std::type_info const* exception_wrapper::uninit_type_( return &typeid(void); } -template -inline exception_wrapper::Buffer::Buffer(in_place_t, Ex&& ex) { - ::new (static_cast(&buff_)) DEx(std::forward(ex)); +template +inline exception_wrapper::Buffer::Buffer(in_place_type_t, As&&... as_) { + ::new (static_cast(&buff_)) Ex(std::forward(as_)...); } template @@ -90,11 +92,48 @@ inline std::exception const* exception_wrapper::as_exception_or_null_( return nullptr; } +static_assert( + !kIsWindows || sizeof(void*) == 8, + "exception_wrapper is untested on 32 bit Windows."); +static_assert( + !kIsWindows || (kMscVer >= 1900 && kMscVer <= 2000), + "exception_wrapper is untested and possibly broken on your version of " + "MSVC"); + inline std::uintptr_t exception_wrapper::ExceptionPtr::as_int_( + std::exception_ptr const& ptr, std::exception const& e) { - return reinterpret_cast(&e); + if (!kIsWindows) { + return reinterpret_cast(&e); + } else { + // On Windows, as of MSVC2017, all thrown exceptions are copied to the stack + // first. Thus, we cannot depend on exception references associated with an + // exception_ptr to be live for the duration of the exception_ptr. We need + // to directly access the heap allocated memory inside the exception_ptr. + // + // std::exception_ptr is an opaque reinterpret_cast of + // std::shared_ptr<__ExceptionPtr> + // __ExceptionPtr is a non-virtual class with two members, a union and a + // bool. The union contains the now-undocumented EHExceptionRecord, which + // contains a struct which contains a void* which points to the heap + // allocated exception. + // We derive the offset to pExceptionObject via manual means. + FOLLY_PACK_PUSH + struct Win32ExceptionPtr { + char offset[40]; + void* exceptionObject; + } FOLLY_PACK_ATTR; + FOLLY_PACK_POP + + auto* win32ExceptionPtr = + reinterpret_cast const*>( + &ptr)->get(); + return reinterpret_cast(win32ExceptionPtr->exceptionObject); + } } -inline std::uintptr_t exception_wrapper::ExceptionPtr::as_int_(AnyException e) { +inline std::uintptr_t exception_wrapper::ExceptionPtr::as_int_( + std::exception_ptr const&, + AnyException e) { return reinterpret_cast(e.typeinfo_) + 1; } inline bool exception_wrapper::ExceptionPtr::has_exception_() const { @@ -241,14 +280,15 @@ inline exception_wrapper exception_wrapper::SharedPtr::get_exception_ptr_( return that->sptr_.ptr_->get_exception_ptr_(); } -template -inline exception_wrapper::exception_wrapper(Ex&& ex, OnHeapTag) - : sptr_{std::make_shared>(std::forward(ex))}, +template +inline exception_wrapper::exception_wrapper(OnHeapTag, in_place_type_t, As&&... as) + : sptr_{std::make_shared>(std::forward(as)...)}, vptr_(&SharedPtr::ops_) {} -template -inline exception_wrapper::exception_wrapper(Ex&& ex, InSituTag) - : buff_{in_place, std::forward(ex)}, vptr_(&InPlace::ops_) {} +template +inline exception_wrapper::exception_wrapper(InSituTag, in_place_type_t, As&&... as) + : buff_{in_place_type, std::forward(as)...}, + vptr_(&InPlace::ops_) {} inline exception_wrapper::exception_wrapper(exception_wrapper&& that) noexcept : exception_wrapper{} { @@ -282,7 +322,7 @@ inline exception_wrapper::~exception_wrapper() { template inline exception_wrapper::exception_wrapper(std::exception_ptr ptr, Ex& ex) - : eptr_{std::move(ptr), ExceptionPtr::as_int_(ex)}, + : eptr_{ptr, ExceptionPtr::as_int_(ptr, ex)}, vptr_(&ExceptionPtr::ops_) { assert(eptr_.ptr_); } @@ -295,7 +335,7 @@ Ex&& dont_slice(Ex&& ex) { "be sliced when storing in exception_wrapper."); return std::forward(ex); } -} +} // namespace exception_wrapper_detail template < class Ex, @@ -306,8 +346,9 @@ template < exception_wrapper::IsRegularExceptionType>::value)> inline exception_wrapper::exception_wrapper(Ex&& ex) : exception_wrapper{ - exception_wrapper_detail::dont_slice(std::forward(ex)), - PlacementOf{}} { + PlacementOf{}, + in_place_type, + exception_wrapper_detail::dont_slice(std::forward(ex))} { } template < @@ -317,8 +358,21 @@ template < exception_wrapper::IsRegularExceptionType::value)> inline exception_wrapper::exception_wrapper(in_place_t, Ex&& ex) : exception_wrapper{ - exception_wrapper_detail::dont_slice(std::forward(ex)), - PlacementOf{}} { + PlacementOf{}, + in_place_type, + exception_wrapper_detail::dont_slice(std::forward(ex))} { +} + +template < + class Ex, + typename... As, + FOLLY_REQUIRES_DEF( + exception_wrapper::IsRegularExceptionType::value)> +inline exception_wrapper::exception_wrapper(in_place_type_t, As&&... as) + : exception_wrapper{ + PlacementOf{}, + in_place_type, + std::forward(as)...} { } inline void exception_wrapper::swap(exception_wrapper& that) noexcept { @@ -405,7 +459,7 @@ inline bool exception_wrapper::is_compatible_with() const noexcept { [[noreturn]] inline void exception_wrapper::throw_exception() const { vptr_->throw_(this); - onNoExceptionError(); + onNoExceptionError(__func__); } template @@ -591,7 +645,7 @@ inline void exception_wrapper::handle(CatchFns... fns) { using AllStdEx = exception_wrapper_detail::AllOf...>; if (!*this) { - onNoExceptionError(); + onNoExceptionError(__func__); } this->handle_(AllStdEx{}, *this, fns...); } @@ -600,7 +654,7 @@ inline void exception_wrapper::handle(CatchFns... fns) const { using AllStdEx = exception_wrapper_detail::AllOf...>; if (!*this) { - onNoExceptionError(); + onNoExceptionError(__func__); } this->handle_(AllStdEx{}, *this, fns...); }