https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97211
Bug ID: 97211
Summary: __cxa_guard_acquire fails to detect recursive init in
multithreaded code
Product: gcc
Version: 11.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: redi at gcc dot gnu.org
Target Milestone: ---
In a single-threaded program this detects recursive init:
#include <stddef.h>
int a() {
static int xx = a();
return 1;
}
extern "C" void* b(void*)
{
a();
return NULL;
}
int main() {
b(NULL);
}
terminate called after throwing an instance of
'__gnu_cxx::recursive_init_error'
what(): std::exception
Aborted (core dumped)
When we know there are no threads in the program we can assume that attempting
to acquire the guard variable when it's already in progress means recursive
init. Because no other thread exists, so it must have been the current thread
that started it, and we've re-entered the initialization.
But if there are multiple threads we just go to sleep waiting forever for
initialization to finish:
#include <pthread.h>
int a() {
static int xx = a();
return 1;
}
extern "C" void* b(void*)
{
a();
return NULL;
}
int main() {
pthread_t thrd;
pthread_create(&thrd, NULL, b, NULL);
pthread_join(thrd, NULL);
}
Clang makes this work by storing the result of SYS_gettid in the last four
bytes of the guard variable, so it can detect when the same thread re-enters
the guard.