diff --git a/include/boost/context/fiber_fcontext.hpp b/include/boost/context/fiber_fcontext.hpp index 543ba6cf..38476c9c 100644 --- a/include/boost/context/fiber_fcontext.hpp +++ b/include/boost/context/fiber_fcontext.hpp @@ -70,7 +70,9 @@ namespace context { namespace detail { // manage_exception_state is a dummy struct unless we have specific support -struct manage_exception_state {}; +struct manage_exception_state { + void from_forced_unwind() noexcept {} +}; } // namespace detail } // namespace context @@ -90,6 +92,11 @@ class manage_exception_state { BOOST_NOINLINE manage_exception_state() { exception_state_ = *__cxa_get_globals(); } + // Hack to account for the forced_unwind exception thrown in fiber_unwind + // that's run ontop before the destructor. + void from_forced_unwind() noexcept { + exception_state_.uncaughtExceptions += 1; + } BOOST_NOINLINE ~manage_exception_state() { *__cxa_get_globals() = exception_state_; } @@ -376,13 +383,18 @@ class fiber { BOOST_ASSERT( nullptr != fctx_); detail::manage_exception_state exstate; boost::ignore_unused(exstate); - return { detail::jump_fcontext( + try { + return { detail::jump_fcontext( #if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), + detail::exchange( fctx_, nullptr), #else - std::exchange( fctx_, nullptr), + std::exchange( fctx_, nullptr), #endif - nullptr).fctx }; + nullptr).fctx }; + } catch ( detail::forced_unwind const& ) { + exstate.from_forced_unwind(); + throw; + } } template< typename Fn > @@ -391,14 +403,19 @@ class fiber { detail::manage_exception_state exstate; boost::ignore_unused(exstate); auto p = std::forward< Fn >( fn); - return { detail::ontop_fcontext( + try { + return { detail::ontop_fcontext( #if defined(BOOST_NO_CXX14_STD_EXCHANGE) - detail::exchange( fctx_, nullptr), + detail::exchange( fctx_, nullptr), #else - std::exchange( fctx_, nullptr), + std::exchange( fctx_, nullptr), #endif - & p, - detail::fiber_ontop< fiber, decltype(p) >).fctx }; + & p, + detail::fiber_ontop< fiber, decltype(p) >).fctx }; + } catch ( detail::forced_unwind const& ) { + exstate.from_forced_unwind(); + throw; + } } explicit operator bool() const noexcept { diff --git a/test/test_fiber.cpp b/test/test_fiber.cpp index e5f1e9e7..0da605fe 100644 --- a/test/test_fiber.cpp +++ b/test/test_fiber.cpp @@ -510,6 +510,29 @@ void test_badcatch() { #endif } +void test_uncaught_exceptions() { + int i = 42; + { + ctx::fiber f{ + [&i](ctx::fiber && f ) { + struct scope_test { + int &i_; + scope_test( int &i) : + i_(i) { + } + ~scope_test() { + i_ = std::uncaught_exceptions(); + } + }; + scope_test scope( i); + return std::move( f).resume(); + i = 84; + }}; + f = std::move(f).resume(); + } + BOOST_CHECK_EQUAL( i, 1); +} + int main() { test_move(); @@ -529,6 +552,7 @@ int main() #endif test_goodcatch(); test_badcatch(); + test_uncaught_exceptions(); return boost::report_errors(); }