Skip to content

Commit 3e8e729

Browse files
authored
rust: preserve WASIp3 TLS for no-std task context (#1745)
* rust: preserve WASIp3 TLS for no-std task context The prebuilt task-context helper was compiled with -mcpu=mvp, which lowers its _Thread_local storage to a plain global. Overlapping async exports on WASIp3 then share the same task state and panic in start_task. Keep wasip3_task_set in the MVP archive used by every wasm32 target. Move the versioned context accessors into a separate archive compiled for wasm32-wasip3 and link it only for that target. Regenerate the C, object, and archive files and check the TLS-base import during rebuilds. Validation: - Stock nightly-2026-10-12 and Wasmtime 47.0.2: the unpatched HTTP handler returns 20/20 concurrent 500s; the fix returns 20/20 200s. - Rust 1.99.0 builds binaries and cdylibs for WASIp1, WASIp2, and wasm32-unknown-unknown without introducing TLS-base imports. - WASIp1/WASIp2 binaries and the unknown-target probe run successfully; native unit tests and the generated doctest pass. - SDK 34 and wasm-tools 1.258.0 regenerate artifacts identically on macOS arm64. Reintroducing the MVP flag makes the rebuild guard fail. - cargo fmt --all --check and git diff --check pass. * rust: link the WASIp3 TLS helper only without std
1 parent 1145d46 commit 3e8e729

8 files changed

Lines changed: 46 additions & 16 deletions

‎ci/rebuild-libwit-bindgen-cabi.sh‎

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ wasip3_set=wit_bindgen_${version}_set_task_context
4848
rm -f crates/guest-rust/src/rt/wit_bindgen_*.{rs,o,c}
4949
rm -f crates/guest-rust/src/rt/libwit_bindgen_cabi_realloc.a
5050
rm -f crates/guest-rust/src/rt/libwit_bindgen_cabi_wasip3.a
51+
rm -f crates/guest-rust/src/rt/libwit_bindgen_cabi_wasip3_tls.a
5152

5253
cat >./crates/guest-rust/src/rt/wit_bindgen_cabi_realloc.rs <<-EOF
5354
// This file is generated by $0
@@ -100,6 +101,15 @@ void *wasip3_task_set(void *ptr) {
100101
WASIP3_TASK = ptr;
101102
return ret;
102103
}
104+
EOF
105+
106+
# On WASIp3, wasi-libc switches TLS blocks between tasks. Compile this helper
107+
# for that target so `_Thread_local` remains TLS; compiling it as MVP would
108+
# silently turn `task_context` into a global shared by all tasks.
109+
cat >./crates/guest-rust/src/rt/wit_bindgen_cabi_wasip3_tls.c <<-EOF
110+
// This file is generated by $0
111+
112+
#include <stddef.h>
103113
104114
static _Thread_local void *task_context = NULL;
105115
@@ -114,19 +124,30 @@ EOF
114124

115125
build() {
116126
file=$1
117-
$WASI_SDK_PATH/bin/clang crates/guest-rust/src/rt/$1.c \
118-
-O -c -o crates/guest-rust/src/rt/$1.o -mcpu=mvp -fPIC
127+
shift
128+
$WASI_SDK_PATH/bin/clang crates/guest-rust/src/rt/$file.c \
129+
-O -c -o crates/guest-rust/src/rt/$file.o -fPIC "$@"
119130
# Remove the `producers` section. This appears to differ whether the host for
120131
# clang is either macOS or Linux. Not needed here anyway, so discard it to help
121132
# either host produce the same object.
122-
wasm-tools strip -d producers ./crates/guest-rust/src/rt/$1.o \
123-
-o ./crates/guest-rust/src/rt/$1.o
133+
wasm-tools strip -d producers ./crates/guest-rust/src/rt/$file.o \
134+
-o ./crates/guest-rust/src/rt/$file.o
124135
}
125136

126-
build wit_bindgen_cabi_realloc
127-
build wit_bindgen_cabi_wasip3
137+
build wit_bindgen_cabi_realloc -mcpu=mvp
138+
build wit_bindgen_cabi_wasip3 -mcpu=mvp
139+
build wit_bindgen_cabi_wasip3_tls --target=wasm32-wasip3
140+
141+
# Catch accidentally compiling the task-local state as a plain global again.
142+
if ! wasm-tools print crates/guest-rust/src/rt/wit_bindgen_cabi_wasip3_tls.o \
143+
| grep -qF '(import "env" "__wasm_get_tls_base"'; then
144+
echo "error: WASIp3 task context must use TLS" >&2
145+
exit 1
146+
fi
128147

129148
$WASI_SDK_PATH/bin/llvm-ar crus crates/guest-rust/src/rt/libwit_bindgen_cabi_realloc.a \
130149
crates/guest-rust/src/rt/wit_bindgen_cabi_realloc.o
131150
$WASI_SDK_PATH/bin/llvm-ar crus crates/guest-rust/src/rt/libwit_bindgen_cabi_wasip3.a \
132151
crates/guest-rust/src/rt/wit_bindgen_cabi_wasip3.o
152+
$WASI_SDK_PATH/bin/llvm-ar crus crates/guest-rust/src/rt/libwit_bindgen_cabi_wasip3_tls.a \
153+
crates/guest-rust/src/rt/wit_bindgen_cabi_wasip3_tls.o

‎crates/guest-rust/build.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ fn main() {
1818
link_lib("cabi_realloc");
1919
}
2020
link_lib("cabi_wasip3");
21+
22+
// The no-std async runtime's task context uses WASIp3 TLS. Keep this
23+
// separate from the MVP task helper needed by every wasm32 target.
24+
if target_env == "p3" && !cfg!(feature = "std") {
25+
link_lib("cabi_wasip3_tls");
26+
}
2127
}
2228

2329
fn link_lib(name: &str) {
-282 Bytes
Binary file not shown.
766 Bytes
Binary file not shown.

‎crates/guest-rust/src/rt/wit_bindgen_cabi_wasip3.c‎

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,3 @@ void *wasip3_task_set(void *ptr) {
1010
WASIP3_TASK = ptr;
1111
return ret;
1212
}
13-
14-
static _Thread_local void *task_context = NULL;
15-
16-
void *wit_bindgen_0_62_0_get_task_context(void) {
17-
return task_context;
18-
}
19-
20-
void wit_bindgen_0_62_0_set_task_context(void *ptr) {
21-
task_context = ptr;
22-
}
-202 Bytes
Binary file not shown.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// This file is generated by ./ci/rebuild-libwit-bindgen-cabi.sh
2+
3+
#include <stddef.h>
4+
5+
static _Thread_local void *task_context = NULL;
6+
7+
void *wit_bindgen_0_62_0_get_task_context(void) {
8+
return task_context;
9+
}
10+
11+
void wit_bindgen_0_62_0_set_task_context(void *ptr) {
12+
task_context = ptr;
13+
}
461 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)