From 460653084492f23388742905ebb884fc673eaabc Mon Sep 17 00:00:00 2001 From: Tudor Bosman Date: Thu, 1 May 2014 19:57:06 -0700 Subject: [PATCH] exception_wrapper: now without undefined behavior Summary: Converting from std::exception* to void* to T* (where T is not std::exception but a derived type) is undefined behavior (and will break with multiple or virtual inheritance). Luckily, there's no need for void* there at all. Also, don't force make_exception_wrapper to capture by value. Test Plan: exception_wrapper_test Reviewed By: marccelani@fb.com FB internal diff: D1308251 @override-unit-failures --- folly/ExceptionWrapper.h | 22 +++++++++++++++------- folly/detail/ExceptionWrapper.h | 6 +++--- folly/test/ExceptionWrapperTest.cpp | 7 +++++++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/folly/ExceptionWrapper.h b/folly/ExceptionWrapper.h index 647c870f..0a232728 100644 --- a/folly/ExceptionWrapper.h +++ b/folly/ExceptionWrapper.h @@ -17,6 +17,7 @@ #ifndef FOLLY_EXCEPTIONWRAPPER_H #define FOLLY_EXCEPTIONWRAPPER_H +#include #include #include #include "folly/detail/ExceptionWrapper.h" @@ -33,23 +34,30 @@ class exception_wrapper { } } - std::exception* get() { - return item_.get(); - } + std::exception* get() { return item_.get(); } + const std::exception* get() const { return item_.get(); } + + std::exception* operator->() { return get(); } + const std::exception* operator->() const { return get(); } + + std::exception& operator*() { assert(get()); return *get(); } + const std::exception& operator*() const { assert(get()); return *get(); } + + explicit operator bool() const { return get(); } private: std::shared_ptr item_; - void (*throwfn_)(void*); + void (*throwfn_)(std::exception*); template - friend exception_wrapper make_exception_wrapper(Args... args); + friend exception_wrapper make_exception_wrapper(Args&&... args); }; template -exception_wrapper make_exception_wrapper(Args... args) { +exception_wrapper make_exception_wrapper(Args&&... args) { exception_wrapper ew; ew.item_ = std::make_shared(std::forward(args)...); - ew.throwfn_ = folly::detail::thrower::doThrow; + ew.throwfn_ = folly::detail::Thrower::doThrow; return ew; } diff --git a/folly/detail/ExceptionWrapper.h b/folly/detail/ExceptionWrapper.h index bc88bf89..4c12834b 100644 --- a/folly/detail/ExceptionWrapper.h +++ b/folly/detail/ExceptionWrapper.h @@ -20,10 +20,10 @@ namespace folly { namespace detail { template -class thrower { +class Thrower { public: - static void doThrow(void* obj) { - throw *((T*)(obj)); + static void doThrow(std::exception* obj) { + throw *static_cast(obj); } }; diff --git a/folly/test/ExceptionWrapperTest.cpp b/folly/test/ExceptionWrapperTest.cpp index 6aad3f15..c20535ee 100644 --- a/folly/test/ExceptionWrapperTest.cpp +++ b/folly/test/ExceptionWrapperTest.cpp @@ -36,3 +36,10 @@ TEST(ExceptionWrapper, throw_test) { EXPECT_EQ(expected, actual); } } + +TEST(ExceptionWrapper, boolean) { + auto ew = exception_wrapper(); + EXPECT_FALSE(bool(ew)); + ew = make_exception_wrapper("payload"); + EXPECT_TRUE(bool(ew)); +} -- 2.34.1