Subject: [Boost-bugs] [Boost C++ Libraries] #10093: Exceptions "teleport" between coroutines when switching inside catch
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2014-06-04 19:04:51
#10093: Exceptions "teleport" between coroutines when switching inside catch
------------------------------+-----------------------
Reporter: snaury@⦠| Owner: olli
Type: Bugs | Status: new
Milestone: To Be Determined | Component: coroutine
Version: Boost 1.54.0 | Severity: Problem
Keywords: |
------------------------------+-----------------------
Sorry for using coroutines v1 API, but the actual API doesn't matter as
much as the result and the reason for it. Consider the following program:
{{{#!cpp
#define BOOST_COROUTINES_V1
#include <boost/coroutine/all.hpp>
#include <exception>
#include <iostream>
typedef boost::coroutines::coroutine<void()> coro_t;
void mycoro(coro_t::caller_type& caller)
{
std::cout << "calling caller..." << std::endl;
caller();
try {
try {
throw std::runtime_error("mycoro exception");
} catch(const std::exception& e) {
std::cout << "calling caller in the catch block..." <<
std::endl;
caller();
std::cout << "rethrowing mycoro exception..." << std::endl;
throw;
}
} catch (const std::exception& e) {
std::cout << "mycoro caught: " << e.what() << std::endl;
}
std::cout << "exiting mycoro..." << std::endl;
}
int main(int argc, char** argv)
{
coro_t callee(mycoro);
try {
try {
throw std::runtime_error("main exception");
} catch(const std::exception& e) {
std::cout << "calling callee in the catch block..." <<
std::endl;
callee();
std::cout << "rethrowing main exception..." << std::endl;
throw;
}
} catch (const std::exception& e) {
std::cout << "main caught: " << e.what() << std::endl;
}
std::cout << "calling callee one last time..." << std::endl;
callee();
std::cout << "exiting main..." << std::endl;
return 0;
}
}}}
When compiled with gcc it causes the following output:
{{{
calling caller...
calling callee in the catch block...
calling caller in the catch block...
rethrowing main exception...
main caught: mycoro exception
calling callee one last time...
rethrowing mycoro exception...
mycoro caught: main exception
exiting mycoro...
exiting main...
}}}
Which shows that boost coroutines are unsafe in the presence of current
exceptions, since in that case exceptions "teleport" between coroutines in
weird ways. The problem here is that caught exceptions are saved in per-
thread globals according to ABI, see: mentorembedded.github.io/cxx-abi
/abi-eh.html (struct __cxa_eh_globals).
It contains two very important fields, pointer to which can be obtained
with __cxx_get_globals() or with __cxx_get_globals_fast() and check for
null result (though the latter is not as reliable). Whenever coroutines
switch they should save and restore those fields to properly support
exceptions and avoid current exception bleeding between coroutines.
This ABI is supported by both gcc and clang, though I'm not sure since
which version.
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/10093> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:16 UTC