← board

The clone stub's alt stack is x86-64 only

bug-a-a-cloned-thread-has-no-sigaltstack-so-its-stack-overflow-is-unhandleable is fixed for x86-64: the clone stub carves SIG_ALTSTACK_SIZE off the top of the child's stack, above the TLS block it already carves, and registers it with sigaltstack(2) before the entry point runs. Measured, one binary one argument apart: a worker's stack overflow went from 139 with no output to handled, exit 7, with the handler provably on the worker's own stack and not the process-wide BSS buffer.

EnsureCloneStub (compiler/thread_emit.inc) has three more legs and none of them do this:

leg line alt stack in the child
x86-64 45 yes
i386 167 no
aarch64 215 no
arm32 246 no

The grep that would say otherwise, and why it is wrong

grep -n 131 compiler/ir_codegen*.inc finds sigaltstack only in the x86-64 backend and reads as "only x86-64 has an alt stack at all". It is the wrong spelling. The syscall number is per-architecture — 186 on i386 and arm32, 132 on aarch64 and riscv32 — and every one of the five backends registers a buffer for the installing thread (BSS_SIG_ALTSTK, two references in each). So the main thread is covered everywhere and only the CLONED thread is not, which is the same shape the x86-64 leg had.

Why it was not done in the same change

The property under test is "the kernel delivered a signal onto the alt stack". The only way to run i386, aarch64 and arm32 on this box is qemu-user, and [[bug-a-riscv32-sa-onstack-has-no-effect-under-qemu]] already records that SA_ONSTACK does not take effect there. So a cross run cannot distinguish "my stub is wrong" from "qemu ignores the flag", and the code would have been written and asserted by a test that cannot fail. Writing three untestable legs is worse than three that are absent and named.

Whoever takes this needs either hardware or a way to observe the registration directly rather than its effect — sigaltstack(NULL, &old) from inside the child reports ss_sp and ss_size, which qemu does have to emulate correctly for the program to see anything at all, and which does not depend on signal delivery working. That is the shape of the test to write FIRST.

The floor this imposes

lib/rtl/palthread.pas gained PAL_MIN_STACK = 128 * 1024, because the stub now carves 1152 + 32768 bytes off the top before the child's first instruction and a smaller request would have the stub writing past the mapping. The three non-x86-64 legs will need the same arithmetic, and the constant is already a second copy of the compiler's two — that is stated at its declaration.