Skip to content

Commit

Permalink
Merge pull request #7848 from Icinga/bugfix/coroutine-exception-211x
Browse files Browse the repository at this point in the history
IoEngine#SpawnCoroutine(): always terminate coroutines cleanly
  • Loading branch information
N-o-X authored Mar 2, 2020
2 parents c02eb62 + 99387dd commit 2a130df
Showing 1 changed file with 10 additions and 26 deletions.
36 changes: 10 additions & 26 deletions lib/base/io-engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
#ifndef IO_ENGINE_H
#define IO_ENGINE_H

#include "base/exception.hpp"
#include "base/lazy-init.hpp"
#include "base/logger.hpp"
#include <atomic>
#include <exception>
#include <memory>
Expand Down Expand Up @@ -79,28 +81,6 @@ class IoEngine

boost::asio::io_context& GetIoContext();

/*
* Custom exceptions thrown in a Boost.Coroutine may cause stack corruption.
* Ensure that these are wrapped correctly.
*
* Inspired by https://github.com/niekbouman/commelec-api/blob/master/commelec-api/coroutine-exception.hpp
* Source: http://boost.2283326.n4.nabble.com/coroutine-only-std-exceptions-are-caught-from-coroutines-td4683671.html
*/
static inline boost::exception_ptr convertExceptionPtr(std::exception_ptr ex) {
try {
throw boost::enable_current_exception(ex);
} catch (...) {
return boost::current_exception();
}
}

static inline void rethrowBoostExceptionPointer() {
std::exception_ptr sep;
sep = std::current_exception();
boost::exception_ptr bep = convertExceptionPtr(sep);
boost::rethrow_exception(bep);
}

static inline size_t GetCoroutineStackSize() {
#ifdef _WIN32
// Increase the stack size for Windows coroutines to prevent exception corruption.
Expand All @@ -124,9 +104,11 @@ class IoEngine
// Required for proper stack unwinding when coroutines are destroyed.
// https://github.com/boostorg/coroutine/issues/39
throw;
} catch (const std::exception& ex) {
Log(LogCritical, "IoEngine", "Exception in coroutine!");
Log(LogDebug, "IoEngine") << "Exception in coroutine: " << DiagnosticInformation(ex);
} catch (...) {
// Handle uncaught exceptions outside of the coroutine.
rethrowBoostExceptionPointer();
Log(LogCritical, "IoEngine", "Exception in coroutine!");
}
},
boost::coroutines::attributes(GetCoroutineStackSize()) // Set a pre-defined stack size.
Expand All @@ -146,9 +128,11 @@ class IoEngine
// Required for proper stack unwinding when coroutines are destroyed.
// https://github.com/boostorg/coroutine/issues/39
throw;
} catch (const std::exception& ex) {
Log(LogCritical, "IoEngine", "Exception in coroutine!");
Log(LogDebug, "IoEngine") << "Exception in coroutine: " << DiagnosticInformation(ex);
} catch (...) {
// Handle uncaught exceptions outside of the coroutine.
rethrowBoostExceptionPointer();
Log(LogCritical, "IoEngine", "Exception in coroutine!");
}
},
boost::coroutines::attributes(GetCoroutineStackSize()) // Set a pre-defined stack size.
Expand Down

0 comments on commit 2a130df

Please sign in to comment.