On Tue, 26 May 2026 00:26:40 +0900,
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(-)
> 
> diff --git ./linux-user/sh4/signal.c ./linux-user/sh4/signal.c
> index d70be24c38..cc36425c49 100644
> --- ./linux-user/sh4/signal.c
> +++ ./linux-user/sh4/signal.c
> @@ -131,8 +131,10 @@ static void setup_sigcontext(struct target_sigcontext 
> *sc,
>      COPY(gregs[14]); COPY(gregs[15]);
>      COPY(gbr); COPY(mach);
>      COPY(macl); COPY(pr);
> -    COPY(sr); COPY(pc);
> +    COPY(pc);
>  #undef COPY
> +    /* The T, M and Q bits live outside env->sr; fold them back in. */
> +    __put_user(cpu_read_sr(regs), &sc->sc_sr);
>  
>      for (i=0; i<16; i++) {
>          __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
> @@ -159,8 +161,14 @@ static void restore_sigcontext(CPUSH4State *regs, struct 
> target_sigcontext *sc)
>      COPY(gregs[14]); COPY(gregs[15]);
>      COPY(gbr); COPY(mach);
>      COPY(macl); COPY(pr);
> -    COPY(sr); COPY(pc);
> +    COPY(pc);
>  #undef COPY
> +    /* The T, M and Q bits live outside env->sr; unfold them. */
> +    {
> +        uint32_t sr;
> +        __get_user(sr, &sc->sc_sr);
> +        cpu_write_sr(regs, sr);
> +    }
>  
>      for (i=0; i<16; i++) {
>          __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
> diff --git ./tests/tcg/sh4/Makefile.target ./tests/tcg/sh4/Makefile.target
> index 7852fa62d8..b7a8737be0 100644
> --- ./tests/tcg/sh4/Makefile.target
> +++ ./tests/tcg/sh4/Makefile.target
> @@ -3,13 +3,6 @@
>  # SuperH specific tweaks
>  #
>  
> -# This triggers failures for sh4-linux about 10% of the time.
> -# Random SIGSEGV at unpredictable guest address, cause unknown.
> -run-signals: signals
> -     $(call skip-test, $<, "BROKEN")
> -run-plugin-signals-with-%:
> -     $(call skip-test, $<, "BROKEN")
> -
>  VPATH += $(SRC_PATH)/tests/tcg/sh4
>  
>  test-macl: CFLAGS += -O -g
> -- 
> 2.53.0
> 

Reviewed-by: Yoshinori Sato <[email protected]>

-- 
Yosinori Sato

Reply via email to