Repository navigation
EDG's exception handling state is process-global, so concurrent threads corrupt it #446
Description
Issue Summary
With the C-generating back end, the exception handling state is held in
ordinary global variables: __curr_eh_stack_entry, __eh_curr_region and
__catch_clause_number (lib_src/eh.h:418-427). Generated code declares
extern struct ... *__curr_eh_stack_entry; and links its frames onto it.
Every function with a try block or objects that need cleanup pushes and pops
frames on this single shared stack, so threads running C++ code at the same
time interleave each other's frames. Throwing in two threads at once crashes
or trips assertions in the runtime. Threads that never throw can also leave
the stack pointing at another thread's popped frame.
In Boost, Boost.Unordered's cfoa_exception_erase_tests and
cfoa_exception_insert_tests abort with an assertion in lib_src/throw.c
on a worker thread. Several other multithreaded tests crash and are probably
the same issue (see below).
Reproducing Source Code
#include <stdexcept>
#include <thread>
static void work() {
for (int i = 0; i < 100000; ++i) {
try {
throw std::runtime_error("x");
} catch (const std::runtime_error &) {
}
}
}
int main() {
std::thread a(work), b(work);
a.join();
b.join();
return 0;
}Command-line Options
EDG_USE_SYSTEM_HEADERS=1 eccp --c++17 eh_threads.cpp -o eh_threads && ./eh_threads
Type of Issue
[Back End] There is a problem with the generated C code.
Additional Details
Expected: exit status 0 (g++ 15.3.1: 0).
Actual: every run fails, with a different symptom each time:
- linux-gcc-release, 3 runs: exit 134 with
Assertion failed in file "/edg/workspace/lib_src/throw.c", line 1529;
exit 134 withAssertion failed in file "/edg/workspace/lib_src/throw.c", line 481
andC++ runtime abort: terminate() called by the exception handling mechanism;
exit 134 withterminate()andAssertion failed in file "/edg/workspace/lib_src/throw.c", line 1228. - linux-gcc-debug, 3 runs: exit 134 (
terminate()), then two segmentation
faults (exit 139).
The problem is in the runtime library's design rather than in the generated C
as such; none of the issue types fits exactly. The state is created as a plain
external variable by make_curr_eh_stack_entry_var (src/lower_eh.c:4755,
sc_extern) and defined with EXTERN in lib_src/eh.h. The
*-multi-thread-* presets are about compiling with several front end threads
(MULTIPLE_THREAD_COMPILATION, EDG_FRONT_END_DAEMON), not about the
runtime. A fix would make this state thread-local (_Thread_local /
__thread) in the runtime and in the declaration the back end generates, on
targets that support TLS.
Boost:
- Confirmed:
libs/unordered/testcfoa_exception_erase_testsand
cfoa_exception_insert_testsabort with
Assertion failed in file "/edg/workspace/lib_src/throw.c", line 1481inside
__throw, called fromstateful_hash::throw_helperon astd::thread
started by the test'sthread_runner. - Probably the same issue (not confirmed one by one):
cfoa_rw_spinlock_test3/6/7/8
(segmentation fault after "No errors detected"), and Boost.Regex
regex_regress_threadedandregex_regress_threaded_no_cache.
Environment: edgcpp/dev-env Docker image (Fedora 43, GCC 15.3.1) on
x86-64, boost branch at c36e03a67c. EDG_USE_SYSTEM_HEADERS=1 makes eccp
use GCC 15's headers (libstdc++) and pass --gnu_version=150301
(bases/docker/dev-env/gcc/edg_eccp_config); eccp already links
-lpthread.
Reproducing (Standard) Configuration(s)
linux-gcc-release
Reproducing (Non-standard) Configuration
No response
I acknowledge that:
- I have checked open issues and existing discussions before filing this report.
- The reproducing source code that I have provided does not depend on headers that I have not included with my submission.
- I have reduced the reproducing source code to the best of my ability.
- I have selected at least one standard configuration or uploaded a non-standard configuration dump.
- I understand code shared via this form is NOT confidential.
- I have permission to share the reproducing source code and grant permission for the project to use the source code (or derivatives of the source code) to create tests.
- I agree that any tests created using the reproducing source code (or deriatives of it) will be licensed under project license unless I included a
LICENSE.txtfile in my.zipor.tar.gzupload. If I included aLICENSE.txtfile, any tests created using the reproducing source code will be governed by the terms of the license I provided instead.
Activity