On 5/25/26 08:26, Matt Turner wrote:
QEMU keeps the SH4 T, M and Q status-register bits outside env->sr, in the dedicated env->sr_t, env->sr_m and env->sr_q fields; cpu_read_sr() folds them back into the architectural SR value and cpu_write_sr() splits them back out.setup_sigcontext() saved the bare env->sr (so the T/M/Q bits were always zero in the signal frame) and restore_sigcontext() wrote the value straight back into env->sr without updating sr_t/sr_m/sr_q. As a result the T bit was never preserved across signal delivery: on sigreturn the interrupted code resumed with whatever T value the signal handler last left behind. Any conditional branch (or addc/subc/rotcl/div1, etc.) immediately following the interrupted instruction could then take the wrong path. This is the cause of the long-standing intermittent failures of the tests/tcg/multiarch/signals.c test on sh4, which was marked BROKEN. With a SIGRTMIN timer firing every millisecond across many threads, the race was hit a few percent of the time and corrupted the guest heap, surfacing as a SIGSEGV in memset, a malloc assertion, or an rseq registration abort. Traced on a deterministic rr recording: a cmp/hi set T=0, the timer signal interrupted the very next instruction (a bf), the handler left T=1, and the resumed bf took glibc calloc's MORECORE_CLEARS branch, using the old top-chunk size as the clear length for a freshly split small chunk and running memset off the end of the heap. Fix setup_sigcontext()/restore_sigcontext() to use cpu_read_sr() and cpu_write_sr() so the T, M and Q bits round-trip correctly, and drop the BROKEN annotation on the sh4 signals test. Fixes: c3b5bc8ab3 ("SH4: Signal handling for the user space emulator, by Magnus Damm.") Cc:[email protected] --- linux-user/sh4/signal.c | 12 ++++++++++-- tests/tcg/sh4/Makefile.target | 7 ------- 2 files changed, 10 insertions(+), 9 deletions(-)
Reviewed-by: Richard Henderson <[email protected]> r~
