X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FExceptionWrapper-inl.h;h=1d74c030d9fbd5e06e98ee4d9b44e956d6731409;hp=175484454bf596968d43f5dfcf19cfc1d74e3474;hb=d5b67c256c7423d74f4794d7fe421ed239807be4;hpb=19e3e9fe724a363e342e92a5b08378900d6ab539 diff --git a/folly/ExceptionWrapper-inl.h b/folly/ExceptionWrapper-inl.h index 17548445..1d74c030 100644 --- a/folly/ExceptionWrapper-inl.h +++ b/folly/ExceptionWrapper-inl.h @@ -18,35 +18,41 @@ * Author: Eric Niebler */ +#include + namespace folly { template -struct exception_wrapper::arg_type2_ {}; +struct exception_wrapper::arg_type_ + : public arg_type_ { +}; template -struct exception_wrapper::arg_type2_ { +struct exception_wrapper::arg_type_ { using type = Arg; }; template -struct exception_wrapper::arg_type2_ { +struct exception_wrapper::arg_type_ { + using type = Arg; +}; +template +struct exception_wrapper::arg_type_ { + using type = Arg; +}; +template +struct exception_wrapper::arg_type_ { using type = Arg; }; template -struct exception_wrapper::arg_type2_ { +struct exception_wrapper::arg_type_ { using type = AnyException; }; template -struct exception_wrapper::arg_type2_ { +struct exception_wrapper::arg_type_ { using type = AnyException; }; - -template -struct exception_wrapper::arg_type_ {}; -template -struct exception_wrapper::arg_type_> - : public arg_type2_ {}; -template -struct exception_wrapper::arg_type_ { - using type = Arg; +template +struct exception_wrapper::arg_type_ { + using type = AnyException; }; template struct exception_wrapper::arg_type_ { @@ -63,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 @@ -86,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 { @@ -237,14 +280,30 @@ 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( + ThrownTag, + in_place_type_t, + As&&... as) + : eptr_{std::make_exception_ptr(Ex(std::forward(as)...)), + reinterpret_cast(std::addressof(typeid(Ex))) + 1u}, + vptr_(&ExceptionPtr::ops_) {} + +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{} { @@ -278,37 +337,57 @@ 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_); } +namespace exception_wrapper_detail { +template +Ex&& dont_slice(Ex&& ex) { + assert(typeid(ex) == typeid(_t>) || + !"Dynamic and static exception types don't match. Exception would " + "be sliced when storing in exception_wrapper."); + return std::forward(ex); +} +} // namespace exception_wrapper_detail + template < class Ex, class Ex_, FOLLY_REQUIRES_DEF( Conjunction< exception_wrapper::IsStdException, - exception_wrapper::IsRegularExceptionType>())> + exception_wrapper::IsRegularExceptionType>::value)> inline exception_wrapper::exception_wrapper(Ex&& ex) - : exception_wrapper{std::forward(ex), PlacementOf{}} { - // Don't slice!!! - assert(typeid(ex) == typeid(Ex_) || - !"Dynamic and static exception types don't match. Exception would " - "be sliced when storing in exception_wrapper."); + : exception_wrapper{ + PlacementOf{}, + in_place_type, + exception_wrapper_detail::dont_slice(std::forward(ex))} { } template < class Ex, class Ex_, FOLLY_REQUIRES_DEF( - exception_wrapper::IsRegularExceptionType())> + exception_wrapper::IsRegularExceptionType::value)> inline exception_wrapper::exception_wrapper(in_place_t, Ex&& ex) - : exception_wrapper{std::forward(ex), PlacementOf{}} { - // Don't slice!!! - assert(typeid(ex) == typeid(Ex_) || - !"Dynamic and static exception types don't match. Exception would " - "be sliced when storing in exception_wrapper."); + : exception_wrapper{ + 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 { @@ -340,6 +419,20 @@ inline std::exception const* exception_wrapper::get_exception() const noexcept { return vptr_->get_exception_(this); } +template +inline Ex* exception_wrapper::get_exception() noexcept { + Ex* object{nullptr}; + with_exception([&](Ex& ex) { object = &ex; }); + return object; +} + +template +inline Ex const* exception_wrapper::get_exception() const noexcept { + Ex const* object{nullptr}; + with_exception([&](Ex const& ex) { object = &ex; }); + return object; +} + inline std::exception_ptr const& exception_wrapper::to_exception_ptr() noexcept { // Computing an exception_ptr is expensive so cache the result. @@ -379,9 +472,9 @@ inline bool exception_wrapper::is_compatible_with() const noexcept { return with_exception([](Ex const&) {}); } -[[noreturn]] inline void exception_wrapper::throwException() const { +[[noreturn]] inline void exception_wrapper::throw_exception() const { vptr_->throw_(this); - onNoExceptionError(); + onNoExceptionError(__func__); } template @@ -494,7 +587,7 @@ inline void exception_wrapper::handle_( bool handled = false; auto impl = exception_wrapper_detail::fold( HandleReduce::value>{&handled}, - [&] { this_.throwException(); }, + [&] { this_.throw_exception(); }, fns...); impl(); } @@ -567,7 +660,7 @@ inline void exception_wrapper::handle(CatchFns... fns) { using AllStdEx = exception_wrapper_detail::AllOf...>; if (!*this) { - onNoExceptionError(); + onNoExceptionError(__func__); } this->handle_(AllStdEx{}, *this, fns...); } @@ -576,7 +669,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...); }