Commit 1d36d464 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Let Future::then call callbacks outside of the catch handler

Summary:
[Folly] Let `Future::then` call callbacks outside of the catch handler.

And `Future::onError`.

This makes the behavior of calls to `Future` callbacks with respect to currently-handled ("active") exceptions consistent - there will not be an active exception by the time the `Future` callback is called. (Unless `Future::then` or `Future::onError`, etc., is itself called with an active exception. Or unless the `Promise` is fulfilled, outside of the `Future` implementation code, with an active exception.)

This will affect any code which tries to call `std::current_exception()` or `throw;` from within a `Future` callback, such as an `onError` handler. That code will crash. (It was incorrect anyway, and relied on misusing Folly Futures.)

Reviewed By: ericniebler

Differential Revision: D4372173

fbshipit-source-id: 600b22e4db63c98358de29a6abcee807fbc53b0f
parent 686092cb
...@@ -205,20 +205,26 @@ Future<T>::thenImplementation(F&& func, detail::argResult<isTry, F, Args...>) { ...@@ -205,20 +205,26 @@ Future<T>::thenImplementation(F&& func, detail::argResult<isTry, F, Args...>) {
setCallback_([ funcm = std::forward<F>(func), pm = std::move(p) ]( setCallback_([ funcm = std::forward<F>(func), pm = std::move(p) ](
Try<T> && t) mutable { Try<T> && t) mutable {
if (!isTry && t.hasException()) { auto ew = [&] {
pm.setException(std::move(t.exception())); if (!isTry && t.hasException()) {
} else { return std::move(t.exception());
try { } else {
auto f2 = funcm(t.template get<isTry, Args>()...); try {
// that didn't throw, now we can steal p auto f2 = funcm(t.template get<isTry, Args>()...);
f2.setCallback_([p = std::move(pm)](Try<B> && b) mutable { // that didn't throw, now we can steal p
p.setTry(std::move(b)); f2.setCallback_([p = std::move(pm)](Try<B> && b) mutable {
}); p.setTry(std::move(b));
} catch (const std::exception& e) { });
pm.setException(exception_wrapper(std::current_exception(), e)); return exception_wrapper();
} catch (...) { } catch (const std::exception& e) {
pm.setException(exception_wrapper(std::current_exception())); return exception_wrapper(std::current_exception(), e);
} catch (...) {
return exception_wrapper(std::current_exception());
}
} }
}();
if (ew) {
pm.setException(std::move(ew));
} }
}); });
...@@ -301,15 +307,21 @@ Future<T>::onError(F&& func) { ...@@ -301,15 +307,21 @@ Future<T>::onError(F&& func) {
setCallback_([ pm = std::move(p), funcm = std::forward<F>(func) ]( setCallback_([ pm = std::move(p), funcm = std::forward<F>(func) ](
Try<T> && t) mutable { Try<T> && t) mutable {
if (!t.template withException<Exn>([&](Exn& e) { if (!t.template withException<Exn>([&](Exn& e) {
try { auto ew = [&] {
auto f2 = funcm(e); try {
f2.setCallback_([pm = std::move(pm)](Try<T> && t2) mutable { auto f2 = funcm(e);
pm.setTry(std::move(t2)); f2.setCallback_([pm = std::move(pm)](Try<T> && t2) mutable {
}); pm.setTry(std::move(t2));
} catch (const std::exception& e2) { });
pm.setException(exception_wrapper(std::current_exception(), e2)); return exception_wrapper();
} catch (...) { } catch (const std::exception& e2) {
pm.setException(exception_wrapper(std::current_exception())); return exception_wrapper(std::current_exception(), e2);
} catch (...) {
return exception_wrapper(std::current_exception());
}
}();
if (ew) {
pm.setException(std::move(ew));
} }
})) { })) {
pm.setTry(std::move(t)); pm.setTry(std::move(t));
...@@ -350,15 +362,21 @@ Future<T>::onError(F&& func) { ...@@ -350,15 +362,21 @@ Future<T>::onError(F&& func) {
setCallback_( setCallback_(
[ pm = std::move(p), funcm = std::forward<F>(func) ](Try<T> t) mutable { [ pm = std::move(p), funcm = std::forward<F>(func) ](Try<T> t) mutable {
if (t.hasException()) { if (t.hasException()) {
try { auto ew = [&] {
auto f2 = funcm(std::move(t.exception())); try {
f2.setCallback_([pm = std::move(pm)](Try<T> t2) mutable { auto f2 = funcm(std::move(t.exception()));
pm.setTry(std::move(t2)); f2.setCallback_([pm = std::move(pm)](Try<T> t2) mutable {
}); pm.setTry(std::move(t2));
} catch (const std::exception& e2) { });
pm.setException(exception_wrapper(std::current_exception(), e2)); return exception_wrapper();
} catch (...) { } catch (const std::exception& e2) {
pm.setException(exception_wrapper(std::current_exception())); return exception_wrapper(std::current_exception(), e2);
} catch (...) {
return exception_wrapper(std::current_exception());
}
}();
if (ew) {
pm.setException(std::move(ew));
} }
} else { } else {
pm.setTry(std::move(t)); pm.setTry(std::move(t));
......
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