Skip to content

cpp-netlib misuses the boost::promise API #815

@HighCommander4

Description

@HighCommander4

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions