-
Notifications
You must be signed in to change notification settings - Fork 425
Description
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.