From 4fee4e238261cc4d5cffddc0a52127b6e586ec07 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 2 Jul 2025 17:48:30 +0000 Subject: [PATCH 1/2] [pthreads] Initialize TLS on workers in MINIMAL_RUNTIME mode. TLS was not initialized on workers causing the tls_base address to be 0 and write to the wrong memory location. Fixes #21528 and is also needed for PR #24565 --- src/postamble_minimal.js | 9 +++-- test/pthread/test_pthread_c_thread_local.c | 35 ++++++++++++++++++++ test/pthread/test_pthread_c_thread_local.out | 3 ++ test/test_core.py | 7 ++++ 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 test/pthread/test_pthread_c_thread_local.c create mode 100644 test/pthread/test_pthread_c_thread_local.out diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index 687059c472c5f..cf7df3e372e36 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -51,7 +51,10 @@ function initRuntime(wasmExports) { #endif #if PTHREADS - if (ENVIRONMENT_IS_PTHREAD) return + if (ENVIRONMENT_IS_PTHREAD) { + PThread.tlsInitFunctions.push(wasmExports['_emscripten_tls_init']); + return; + } #endif #if WASM_WORKERS @@ -66,10 +69,6 @@ function initRuntime(wasmExports) { writeStackCookie(); #endif -#if PTHREADS - PThread.tlsInitFunctions.push(wasmExports['_emscripten_tls_init']); -#endif - <<< ATINITS >>> #if hasExportedSymbol('__wasm_call_ctors') diff --git a/test/pthread/test_pthread_c_thread_local.c b/test/pthread/test_pthread_c_thread_local.c new file mode 100644 index 0000000000000..2212d36304796 --- /dev/null +++ b/test/pthread/test_pthread_c_thread_local.c @@ -0,0 +1,35 @@ +// Copyright 2025 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +#include +#include +#include +#include + +static _Thread_local int thread_local = 0; + +void *thread_start(void *arg) { + thread_local = 1; + assert(thread_local == 1); + printf("thread_local=%d\n", thread_local); + return NULL; +} + +int main() { + thread_local = 2; + pthread_t thread; + int rc; + + rc = pthread_create(&thread, NULL, thread_start, NULL); + assert(rc == 0); + + rc = pthread_join(thread, NULL); + assert(rc == 0); + + printf("thread_local=%d\n", thread_local); + assert(thread_local == 2); + printf("done\n"); + return 0; +} diff --git a/test/pthread/test_pthread_c_thread_local.out b/test/pthread/test_pthread_c_thread_local.out new file mode 100644 index 0000000000000..50443a5530ef4 --- /dev/null +++ b/test/pthread/test_pthread_c_thread_local.out @@ -0,0 +1,3 @@ +thread_local=1 +thread_local=2 +done diff --git a/test/test_core.py b/test/test_core.py index c28ce4cbf3c68..d4374ed35dc07 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -2636,6 +2636,13 @@ def test_pthread_thread_local_storage(self): self.set_setting('INITIAL_MEMORY', '300mb') self.do_run_in_out_file_test('pthread/test_pthread_thread_local_storage.cpp') + @node_pthreads + @also_with_minimal_runtime + def test_pthread_c_thread_local(self): + if self.get_setting('MINIMAL_RUNTIME') and is_sanitizing(self.cflags): + self.skipTest('MINIMAL_RUNTIME + threads + asan does not work') + self.do_run_in_out_file_test('pthread/test_pthread_c_thread_local.c') + @node_pthreads def test_pthread_cleanup(self): self.set_setting('PTHREAD_POOL_SIZE', 4) From a5371b7af45b30080197f8a6b3217e42e76c945c Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 2 Jul 2025 21:16:33 +0000 Subject: [PATCH 2/2] also init on main thread --- src/postamble_minimal.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index cf7df3e372e36..247d1a4c765e3 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -51,10 +51,8 @@ function initRuntime(wasmExports) { #endif #if PTHREADS - if (ENVIRONMENT_IS_PTHREAD) { - PThread.tlsInitFunctions.push(wasmExports['_emscripten_tls_init']); - return; - } + PThread.tlsInitFunctions.push(wasmExports['_emscripten_tls_init']); + if (ENVIRONMENT_IS_PTHREAD) return; #endif #if WASM_WORKERS