Skip to content

Commit 779a444

Browse files
[libc] fix tls teardown while being used (#108229)
The call chain to `Mutex:lock` can be polluted by stack protector. For completely safe, let's postpone the main TLS tearing down to a separate phase. fix #108030
1 parent a54efdb commit 779a444

File tree

3 files changed

+14
-6
lines changed

3 files changed

+14
-6
lines changed

libc/src/stdlib/atexit.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace LIBC_NAMESPACE_DECL {
1616

1717
constinit ExitCallbackList atexit_callbacks;
1818
Mutex handler_list_mtx(false, false, false, false);
19+
[[gnu::weak]] extern void teardown_main_tls();
1920

2021
extern "C" {
2122

@@ -24,8 +25,11 @@ int __cxa_atexit(AtExitCallback *callback, void *payload, void *) {
2425
}
2526

2627
void __cxa_finalize(void *dso) {
27-
if (!dso)
28+
if (!dso) {
2829
call_exit_callbacks(atexit_callbacks);
30+
if (teardown_main_tls)
31+
teardown_main_tls();
32+
}
2933
}
3034

3135
} // extern "C"

libc/src/stdlib/quick_exit.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
namespace LIBC_NAMESPACE_DECL {
1717

1818
extern ExitCallbackList at_quick_exit_callbacks;
19+
[[gnu::weak]] extern void teardown_main_tls();
1920

2021
[[noreturn]] LLVM_LIBC_FUNCTION(void, quick_exit, (int status)) {
2122
call_exit_callbacks(at_quick_exit_callbacks);
23+
if (teardown_main_tls)
24+
teardown_main_tls();
2225
internal::exit(status);
2326
}
2427

libc/startup/linux/do_start.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88
#include "startup/linux/do_start.h"
9+
#include "config/linux/app.h"
910
#include "include/llvm-libc-macros/link-macros.h"
1011
#include "src/__support/OSUtil/syscall.h"
1112
#include "src/__support/macros/config.h"
@@ -60,6 +61,10 @@ static void call_fini_array_callbacks() {
6061
}
6162

6263
static ThreadAttributes main_thread_attrib;
64+
static TLSDescriptor tls;
65+
// We separate teardown_main_tls from callbacks as callback function themselves
66+
// may require TLS.
67+
void teardown_main_tls() { cleanup_tls(tls.addr, tls.size); }
6368

6469
[[noreturn]] void do_start() {
6570
auto tid = syscall_impl<long>(SYS_gettid);
@@ -122,18 +127,14 @@ static ThreadAttributes main_thread_attrib;
122127

123128
// This descriptor has to be static since its cleanup function cannot
124129
// capture the context.
125-
static TLSDescriptor tls;
126130
init_tls(tls);
127131
if (tls.size != 0 && !set_thread_ptr(tls.tp))
128132
syscall_impl<long>(SYS_exit, 1);
129133

130134
self.attrib = &main_thread_attrib;
131135
main_thread_attrib.atexit_callback_mgr =
132136
internal::get_thread_atexit_callback_mgr();
133-
// We register the cleanup_tls function to be the last atexit callback to be
134-
// invoked. It will tear down the TLS. Other callbacks may depend on TLS (such
135-
// as the stack protector canary).
136-
atexit([]() { cleanup_tls(tls.addr, tls.size); });
137+
137138
// We want the fini array callbacks to be run after other atexit
138139
// callbacks are run. So, we register them before running the init
139140
// array callbacks as they can potentially register their own atexit

0 commit comments

Comments
 (0)