On Sat, 8 Nov 2025, Takashi Yano via Cygwin wrote:

> I looked into the problem, and found that the executable for
> the following code registers two pthread_keys with each destructor;
> one is void emutls_destroy(void *ptr) in libgcc/emutls.c, and the
> other is void run(void *p) in libstdc++-v3/libsupc++/atexit_thread.cc.
> emutls_destroy() free's the memory erea of static thread_local X,
> that is accessed from X::~X() which is called from run(). As a result,
> if the emutls_destroy() is called before run(), run() referres to
> the memory erea already free'ed.
>
> I think this is a bug of gcc. This issue does not occur in Linux,
> because Linux does not use emutls.


There is a similar longstanding issue in mingw-w64.  The problem there is
that the pthread_key destructors run before the native Windows TLS
callbacks.  emutls still uses pthread_key to manage static thread_locals,
but C++ destructors are called from the Windows TLS callbacks (by way of
__cxa_thread_atexit if memory serves).

Cygwin should have it comparatively easy: it controls all the pieces (it
doesn't need to care about when Windows TLS callbacks happen because if
somebody calls ExitThread they get the undefined behavior they deserve).
Couldn't Cygwin simply provide its own __cxa_thread_atexit and ensure
destructors registered there run before pthread_key destructors?

Regardless, is it really undefined in what order pthread_key destructors
run?  I would expect they'd run in reverse order of registration (most
recently registered first).  Wouldn't that prevent this issue too
(without mucking about with the Itanium C++ ABI)?

-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to