Commit 46065308 authored by Tudor Bosman's avatar Tudor Bosman Committed by Dave Watson

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
parent 7fda1f29
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#ifndef FOLLY_EXCEPTIONWRAPPER_H #ifndef FOLLY_EXCEPTIONWRAPPER_H
#define FOLLY_EXCEPTIONWRAPPER_H #define FOLLY_EXCEPTIONWRAPPER_H
#include <cassert>
#include <exception> #include <exception>
#include <memory> #include <memory>
#include "folly/detail/ExceptionWrapper.h" #include "folly/detail/ExceptionWrapper.h"
...@@ -33,23 +34,30 @@ class exception_wrapper { ...@@ -33,23 +34,30 @@ class exception_wrapper {
} }
} }
std::exception* get() { std::exception* get() { return item_.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: private:
std::shared_ptr<std::exception> item_; std::shared_ptr<std::exception> item_;
void (*throwfn_)(void*); void (*throwfn_)(std::exception*);
template <class T, class... Args> template <class T, class... Args>
friend exception_wrapper make_exception_wrapper(Args... args); friend exception_wrapper make_exception_wrapper(Args&&... args);
}; };
template <class T, class... Args> template <class T, class... Args>
exception_wrapper make_exception_wrapper(Args... args) { exception_wrapper make_exception_wrapper(Args&&... args) {
exception_wrapper ew; exception_wrapper ew;
ew.item_ = std::make_shared<T>(std::forward<Args>(args)...); ew.item_ = std::make_shared<T>(std::forward<Args>(args)...);
ew.throwfn_ = folly::detail::thrower<T>::doThrow; ew.throwfn_ = folly::detail::Thrower<T>::doThrow;
return ew; return ew;
} }
......
...@@ -20,10 +20,10 @@ ...@@ -20,10 +20,10 @@
namespace folly { namespace detail { namespace folly { namespace detail {
template <class T> template <class T>
class thrower { class Thrower {
public: public:
static void doThrow(void* obj) { static void doThrow(std::exception* obj) {
throw *((T*)(obj)); throw *static_cast<T*>(obj);
} }
}; };
......
...@@ -36,3 +36,10 @@ TEST(ExceptionWrapper, throw_test) { ...@@ -36,3 +36,10 @@ TEST(ExceptionWrapper, throw_test) {
EXPECT_EQ(expected, actual); EXPECT_EQ(expected, actual);
} }
} }
TEST(ExceptionWrapper, boolean) {
auto ew = exception_wrapper();
EXPECT_FALSE(bool(ew));
ew = make_exception_wrapper<std::runtime_error>("payload");
EXPECT_TRUE(bool(ew));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment