From 3fc0e18ee8648805f58f75c30f7c7ee1f552212f Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Tue, 14 Jul 2026 21:13:37 -0400 Subject: [PATCH 1/2] task: Add missing write-barrier in `save_stack` --- src/task.c | 1 + test/threads.jl | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/task.c b/src/task.c index 7bba3ee3d83b1..c26b1f167012a 100644 --- a/src/task.c +++ b/src/task.c @@ -189,6 +189,7 @@ static void NOINLINE save_stack(jl_ptls_t ptls, jl_task_t *lastt, jl_task_t **pt if (lastt->ctx.bufsz < nb) { asan_free_copy_stack(lastt->ctx.stkbuf, lastt->ctx.bufsz); buf = (void*)jl_gc_alloc_buf(ptls, nb); + jl_gc_wb(lastt, buf); lastt->ctx.stkbuf = buf; lastt->ctx.bufsz = nb; } diff --git a/test/threads.jl b/test/threads.jl index 541459d04617a..10d579923f9db 100644 --- a/test/threads.jl +++ b/test/threads.jl @@ -587,3 +587,21 @@ let once = OncePerTask{Int}(() -> error("expected")) @test_throws ErrorException("expected") once() @test_throws ErrorException("expected") once() end + +# Exercise `save_stack`/`restore_stack` under GC pressure: a missing write-barrier +# when storing the freshly-allocated copy-stack buffer into `lastt->ctx.stkbuf` +# let the GC collect the buffer while the (old) task still referenced it. +let code = """ + function f(x) + x in (0, 1) && return x + a = Threads.@spawn f(x - 2) + b = Threads.@spawn f(x - 1) + return fetch(a) + fetch(b) + end + print(@sync f(25)) + """ + cmd = addenv(`$(Base.julia_cmd()) --depwarn=error --startup-file=no -t4 -e $code`, + "JULIA_COPY_STACKS" => "1") + # JULIA_COPY_STACKS is broken on Windows (#35147) + @test read(cmd, String) == "75025" skip=Sys.iswindows() +end From d1fde87403a5688782b16786eeb9d911f93c6422 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Wed, 15 Jul 2026 10:16:25 -0400 Subject: [PATCH 2/2] task: Fix `stackbase` alignment Regressed in #55515 --- src/task.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/task.c b/src/task.c index c26b1f167012a..780188b1163b8 100644 --- a/src/task.c +++ b/src/task.c @@ -1594,7 +1594,7 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) if (always_copy_stacks) { // when this is set, we will attempt to corrupt the process stack to switch tasks, // although this is unreliable, and thus not recommended - ptls->stackbase = jl_get_frame_addr(); + ptls->stackbase = (void*)((uintptr_t)jl_get_frame_addr() & ~(uintptr_t)15); ptls->stacksize = (char*)ptls->stackbase - (char*)stack_lo; } else {