cpp-netlib calls boost::promise::set_exception() with a std::exception_ptr as argument in a number of places (for example, in http_async_connection::handle_received_data().
boost::promise::set_exception() has two overloads:
void set_exception(boost::exception_ptr e);
template <typename E>
void set_exception(E e);
The first overload takes a boost::exception_ptr (note: not std::exception_ptr) wrapping a concrete exception. The second overload accepts a concrete exception object itself (and internally wraps it in boost::exception_ptr).
When set_exception() is called with an argument of type std::exception_ptr, the second overload is matched, so boost::promise treats std::exception_ptr as the concrete exception type.
The reason this is a problem (besides the inefficiency of wrapping an exception in two layers of exception pointers), is that when the other side (future::get()) throws the exception, the thrown exception object will be the std::exception_ptr itself, not the concrete exception object that it wraps.
For example, suppose the concrete exception type is boost::system::system_error (as is the case in http_async_connection::handle_received_data()). While the client code may be expecting to catch it with a catch clause like this:
catch (boost::system::system_error& e) {
...
}
in fact this catch clause will not be matched, because the thrown type was std::exception_ptr.
The fix is simple: when calling boost::promise::set_exception(), don't wrap the concrete exception type with std::make_exception_ptr: just pass the concrete exception object directly.
cpp-netlib calls
boost::promise::set_exception()with astd::exception_ptras argument in a number of places (for example, inhttp_async_connection::handle_received_data().boost::promise::set_exception()has two overloads:The first overload takes a
boost::exception_ptr(note: notstd::exception_ptr) wrapping a concrete exception. The second overload accepts a concrete exception object itself (and internally wraps it inboost::exception_ptr).When
set_exception()is called with an argument of typestd::exception_ptr, the second overload is matched, soboost::promisetreatsstd::exception_ptras the concrete exception type.The reason this is a problem (besides the inefficiency of wrapping an exception in two layers of exception pointers), is that when the other side (
future::get()) throws the exception, the thrown exception object will be thestd::exception_ptritself, not the concrete exception object that it wraps.For example, suppose the concrete exception type is
boost::system::system_error(as is the case inhttp_async_connection::handle_received_data()). While the client code may be expecting to catch it with a catch clause like this:in fact this catch clause will not be matched, because the thrown type was
std::exception_ptr.The fix is simple: when calling
boost::promise::set_exception(), don't wrap the concrete exception type withstd::make_exception_ptr: just pass the concrete exception object directly.