[libcxx-commits] [libcxxabi] [libc++abi] Revert gating of `__cxa_thread_atexit` on Linux||Fuchsia (PR #186054)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 4 06:53:38 PDT 2026


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/186054

>From 46301f073b8cc85ad0d2f1dcdda923209bff173b Mon Sep 17 00:00:00 2001
From: Catherine <whitequark at whitequark.org>
Date: Thu, 12 Mar 2026 08:19:49 +0000
Subject: [PATCH 1/6] [libc++abi] Revert gating of `__cxa_thread_atexit` on
 Wasm/WASI

This was done in the commit 3c100d5d548d with the description
"Enable -Wmissing-prototypes" which seems incongruent to me.

Since then it's made its way into a release and broke the use of
`thread_local` variables with destructors on Wasm/WASI:

```cc
// repro.cc
struct c { ~c() {} };
thread_local c v;
int main() { (void)v; }
```

```console
$ ./wasi-sdk-31.0-x86_64-linux/bin/clang++ repro.cc
wasm-ld: error: /tmp/repro-dd1ad7.o: undefined symbol: __cxa_thread_atexit
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
```
---
 libcxxabi/src/cxa_thread_atexit.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libcxxabi/src/cxa_thread_atexit.cpp b/libcxxabi/src/cxa_thread_atexit.cpp
index 402a52c741012..099be242c6dc6 100644
--- a/libcxxabi/src/cxa_thread_atexit.cpp
+++ b/libcxxabi/src/cxa_thread_atexit.cpp
@@ -106,7 +106,7 @@ namespace {
 
 #endif // HAVE___CXA_THREAD_ATEXIT_IMPL
 
-#if defined(__linux__) || defined(__Fuchsia__)
+#if defined(__linux__) || defined(__Fuchsia__) || defined(__wasm__)
 extern "C" {
 
   _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() {
@@ -141,6 +141,7 @@ extern "C" {
     }
 #endif // HAVE___CXA_THREAD_ATEXIT_IMPL
   }
+
 } // extern "C"
-#endif // defined(__linux__) || defined(__Fuchsia__)
+#endif // defined(__linux__) || defined(__Fuchsia__) || defined(__wasm__)
 } // namespace __cxxabiv1

>From c15c52ff34166b3ad5deb6633a897c2e6e5f2b0f Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 3 Aug 2026 16:40:57 -0400
Subject: [PATCH 2/6] Make header consistent with .cpp file

---
 libcxxabi/include/cxxabi.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h
index 66301d308282d..c8a2c3b7b8935 100644
--- a/libcxxabi/include/cxxabi.h
+++ b/libcxxabi/include/cxxabi.h
@@ -179,7 +179,7 @@ __cxa_decrement_exception_refcount(void *primary_exception) _LIBCXXABI_NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() _LIBCXXABI_NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() _LIBCXXABI_NOEXCEPT;
 
-#if defined(__linux__) || defined(__Fuchsia__)
+#if defined(__linux__) || defined(__Fuchsia__) || defined(__wasm__)
 // Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI.
 // https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables
 extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void *), void *,

>From edecf53f872925bb01316509a016b7d0ea783a67 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 3 Aug 2026 16:47:31 -0400
Subject: [PATCH 3/6] Move logic to source file, not CMake

---
 libcxxabi/src/CMakeLists.txt        |  8 +-------
 libcxxabi/src/cxa_thread_atexit.cpp | 17 ++++++++++-------
 2 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/libcxxabi/src/CMakeLists.txt b/libcxxabi/src/CMakeLists.txt
index dd23e9bb5bf79..8f779d913e0a9 100644
--- a/libcxxabi/src/CMakeLists.txt
+++ b/libcxxabi/src/CMakeLists.txt
@@ -9,6 +9,7 @@ set(LIBCXXABI_SOURCES
   cxa_handlers.cpp
   cxa_vector.cpp
   cxa_virtual.cpp
+  cxa_thread_atexit.cpp
   # C++ STL files
   stdlib_exception.cpp
   stdlib_stdexcept.cpp
@@ -36,13 +37,6 @@ else()
   )
 endif()
 
-if (LIBCXXABI_ENABLE_THREADS AND (UNIX OR FUCHSIA) AND NOT (APPLE OR CYGWIN)
-    AND NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "AIX"))
-  list(APPEND LIBCXXABI_SOURCES
-    cxa_thread_atexit.cpp
-  )
-endif()
-
 set(LIBCXXABI_HEADERS
   ../include/cxxabi.h
 )
diff --git a/libcxxabi/src/cxa_thread_atexit.cpp b/libcxxabi/src/cxa_thread_atexit.cpp
index 099be242c6dc6..66c86426ba204 100644
--- a/libcxxabi/src/cxa_thread_atexit.cpp
+++ b/libcxxabi/src/cxa_thread_atexit.cpp
@@ -6,16 +6,18 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "abort_message.h"
 #include "cxxabi.h"
+
+#if !defined(_LIBCXXABI_HAS_NO_THREADS) && defined(__linux__) || defined(__Fuchsia__) || defined(__wasm__)
+
 #include <__thread/support.h>
-#ifndef _LIBCXXABI_HAS_NO_THREADS
+#include <stdlib.h>
+
+#include "abort_message.h"
+
 #if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
 #pragma comment(lib, "pthread")
 #endif
-#endif
-
-#include <stdlib.h>
 
 namespace __cxxabiv1 {
 
@@ -106,7 +108,6 @@ namespace {
 
 #endif // HAVE___CXA_THREAD_ATEXIT_IMPL
 
-#if defined(__linux__) || defined(__Fuchsia__) || defined(__wasm__)
 extern "C" {
 
   _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() {
@@ -143,5 +144,7 @@ extern "C" {
   }
 
 } // extern "C"
-#endif // defined(__linux__) || defined(__Fuchsia__) || defined(__wasm__)
+
 } // namespace __cxxabiv1
+
+#endif // !defined(_LIBCXXABI_HAS_NO_THREADS) && defined(__linux__) || defined(__Fuchsia__) || defined(__wasm__)

>From 07bda8b5a8bad05073af7f7b5f87915083dae872 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 3 Aug 2026 17:09:29 -0400
Subject: [PATCH 4/6] Opt-out instead of opt-in

---
 libcxxabi/include/__cxxabi_config.h | 8 ++++++++
 libcxxabi/src/cxa_thread_atexit.cpp | 4 ++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index 6ec10e469387e..01037fdbe8949 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -134,4 +134,12 @@
 #  define _LIBCXXABI_DISABLE_POINTER_FIELD_PROTECTION
 #endif
 
+// On Apple, Clang generates calls to _tlv_atexit and __cxa_thread_atexit is defined
+// in libc instead.
+//
+// AIX uses a different mechanism for registering thread local destructors (__pt_atexit_np).
+#if !defined(__APPLE__) && !defined(_AIX)
+#  define _LIBCXXABI_DEFINE_THREAD_ATEXIT
+#endif
+
 #endif // ____CXXABI_CONFIG_H
diff --git a/libcxxabi/src/cxa_thread_atexit.cpp b/libcxxabi/src/cxa_thread_atexit.cpp
index 66c86426ba204..cf186ddc80718 100644
--- a/libcxxabi/src/cxa_thread_atexit.cpp
+++ b/libcxxabi/src/cxa_thread_atexit.cpp
@@ -8,7 +8,7 @@
 
 #include "cxxabi.h"
 
-#if !defined(_LIBCXXABI_HAS_NO_THREADS) && defined(__linux__) || defined(__Fuchsia__) || defined(__wasm__)
+#if !defined(_LIBCXXABI_HAS_NO_THREADS) && defined(_LIBCXXABI_DEFINE_THREAD_ATEXIT)
 
 #include <__thread/support.h>
 #include <stdlib.h>
@@ -147,4 +147,4 @@ extern "C" {
 
 } // namespace __cxxabiv1
 
-#endif // !defined(_LIBCXXABI_HAS_NO_THREADS) && defined(__linux__) || defined(__Fuchsia__) || defined(__wasm__)
+#endif // !defined(_LIBCXXABI_HAS_NO_THREADS) && defined(_LIBCXXABI_DEFINE_THREAD_ATEXIT)

>From ab564448f85ccb31499bb3b50613a260844d5742 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 3 Aug 2026 17:11:01 -0400
Subject: [PATCH 5/6] Update header

---
 libcxxabi/include/cxxabi.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h
index c8a2c3b7b8935..f12ce8a01576b 100644
--- a/libcxxabi/include/cxxabi.h
+++ b/libcxxabi/include/cxxabi.h
@@ -179,8 +179,8 @@ __cxa_decrement_exception_refcount(void *primary_exception) _LIBCXXABI_NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() _LIBCXXABI_NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() _LIBCXXABI_NOEXCEPT;
 
-#if defined(__linux__) || defined(__Fuchsia__) || defined(__wasm__)
-// Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI.
+#if defined(_LIBCXXABI_DEFINE_THREAD_ATEXIT)
+// Register a thread local destructor. This is not yet an official part of the Itanium ABI.
 // https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables
 extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void *), void *,
                                                    void *) _LIBCXXABI_NOEXCEPT;

>From 9eb67b35749639f66e8ebd98e72072bd9639f963 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 4 Aug 2026 09:52:37 -0400
Subject: [PATCH 6/6] Use 0-1 macro

---
 libcxxabi/include/__cxxabi_config.h | 11 +++++++----
 libcxxabi/include/cxxabi.h          |  2 +-
 libcxxabi/src/cxa_thread_atexit.cpp |  4 ++--
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index 01037fdbe8949..1b40ccf7d0a55 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -135,11 +135,14 @@
 #endif
 
 // On Apple, Clang generates calls to _tlv_atexit and __cxa_thread_atexit is defined
-// in libc instead.
+// in libc instead. AIX uses a different mechanism for registering thread local
+// destructors (__pt_atexit_np).
 //
-// AIX uses a different mechanism for registering thread local destructors (__pt_atexit_np).
-#if !defined(__APPLE__) && !defined(_AIX)
-#  define _LIBCXXABI_DEFINE_THREAD_ATEXIT
+// On other platforms, libc++abi provides __cxa_thread_atexit.
+#if defined(__APPLE__) || defined(_AIX)
+#  define _LIBCXXABI_DEFINE_THREAD_ATEXIT 0
+#else
+#  define _LIBCXXABI_DEFINE_THREAD_ATEXIT 1
 #endif
 
 #endif // ____CXXABI_CONFIG_H
diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h
index f12ce8a01576b..5d0513c4ccd66 100644
--- a/libcxxabi/include/cxxabi.h
+++ b/libcxxabi/include/cxxabi.h
@@ -179,7 +179,7 @@ __cxa_decrement_exception_refcount(void *primary_exception) _LIBCXXABI_NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() _LIBCXXABI_NOEXCEPT;
 extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() _LIBCXXABI_NOEXCEPT;
 
-#if defined(_LIBCXXABI_DEFINE_THREAD_ATEXIT)
+#if _LIBCXXABI_DEFINE_THREAD_ATEXIT
 // Register a thread local destructor. This is not yet an official part of the Itanium ABI.
 // https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables
 extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void *), void *,
diff --git a/libcxxabi/src/cxa_thread_atexit.cpp b/libcxxabi/src/cxa_thread_atexit.cpp
index cf186ddc80718..3ddca2ddfb229 100644
--- a/libcxxabi/src/cxa_thread_atexit.cpp
+++ b/libcxxabi/src/cxa_thread_atexit.cpp
@@ -8,7 +8,7 @@
 
 #include "cxxabi.h"
 
-#if !defined(_LIBCXXABI_HAS_NO_THREADS) && defined(_LIBCXXABI_DEFINE_THREAD_ATEXIT)
+#if !defined(_LIBCXXABI_HAS_NO_THREADS) && _LIBCXXABI_DEFINE_THREAD_ATEXIT
 
 #include <__thread/support.h>
 #include <stdlib.h>
@@ -147,4 +147,4 @@ extern "C" {
 
 } // namespace __cxxabiv1
 
-#endif // !defined(_LIBCXXABI_HAS_NO_THREADS) && defined(_LIBCXXABI_DEFINE_THREAD_ATEXIT)
+#endif // !defined(_LIBCXXABI_HAS_NO_THREADS) && _LIBCXXABI_DEFINE_THREAD_ATEXIT



More information about the libcxx-commits mailing list