@samitouri / QOSamiQemu / commits / c0e370474b

linux-user/sparc: Take pending signals in sparc64_set_context()

Every callsite of block_signals() checks its return value, except the one in sparc64_set_context(). Generally you need to check, because the standard pattern is: if (block_signals()) { return -QEMU_ERESTARTSYS; } /* do some blocking syscall */ and we need to take any pending signal before we do the blocking operation, not afterwards. The use in sparc64_set_context() doesn't do this. It doesn't have to because the operations it is doing aren't blocking, so it won't get into "we didn't take the signal that we should have" races that blocking syscalls do. But it does make this way of updating the signal mask inconsistent with how we do it in do_sigprocmask(). do_sigprocmask() does the usual "return -QEMU_ERESTARTSYS", so a pending signal that was not blocked by the old signal mask and which will be blocked by the new mask we're about to install will be taken before we change the mask. sparc64_set_context() doesn't check the return value, so we won't take that pending signal. That's not wrong, because it just means the signal lost the race with the executing code. But it seems clearer to behave the same way as do_sigprocmask(), not differently. Make sparc64_set_context() check the return value of block_signals() and return early if there's a pending signal to take. We don't need to return a separate return code to indicate this because the main loop handles it the same either way. Coverity CID: 1660058 Fixes: e0f0ce88eb9 ("linux-user/sparc: call block_signals() before set_sigmask() in setcontext") Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Helge Deller <deller@gmx.de>

Peter Maydell committed Jul 13, 2026 at 15:14 UTC c0e370474b020e4740c85c246e26ec8af1d9d53d
2 files changed +31 -9
linux-user/sparc/cpu_loop.c
+10
@@ -282,6 +282,16 @@ void cpu_loop (CPUSPARCState *env)
282 break;
283 case TT_TRAP + 0x6f:
284 flush_windows(env);
285 + /*
286 + * If we have a pending signal, sparc64_set_context() may
287 + * return early without changing register state (like a
288 + * syscall that returns -QEMU_ERESTARTSYS). We will then
289 + * take the pending signal via process_pending_signals()
290 + * below and eventually re-execute the trap. We don't need
291 + * the function to return a different value for the
292 + * "restart" case because this main loop code does the
293 + * same thing in both cases.
294 + */
295 sparc64_set_context(env);
296 break;
297 #endif
linux-user/sparc/signal.c
+21 -9
@@ -594,6 +594,27 @@ void sparc64_set_context(CPUSPARCState *env)
594 unsigned int i;
595 unsigned char fenab;
596
597 + if (env->regwptr[WREG_O1]) {
598 + /*
599 + * We're going to set the signal mask; we need to call
600 + * block_signals() first, so that process_pending_signals() is
601 + * guaranteed to run after the mask change. Without this, a
602 + * guest signal that is pending-and-blocked at setcontext time
603 + * is left undelivered even after its mask bit is cleared,
604 + * because signal_pending stays 0 and the post-trap
605 + * process_pending_signals() loop never enters.
606 + *
607 + * If block_signals() returns true, this means we have a
608 + * pending signal that we could take now; we return early so
609 + * the cpu_loop takes that signal. Eventually the guest will
610 + * re-execute the trap insn and we'll come back here to have
611 + * another go at set_context. This is the same way that
612 + * do_sigprocmask() handles setting the signal mask.
613 + */
614 + if (block_signals()) {
615 + return;
616 + }
617 + }
618 ucp_addr = env->regwptr[WREG_O0];
619 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
620 goto do_sigsegv;
@@ -619,15 +640,6 @@ void sparc64_set_context(CPUSPARCState *env)
640 }
641 }
642 target_to_host_sigset_internal(&set, &target_set);
622 - /*
623 - * set_sigmask() requires the caller to have first called
624 - * block_signals() so that process_pending_signals() is guaranteed
625 - * to run after the mask change. Without this, a guest signal that
626 - * is pending-and-blocked at setcontext time is left undelivered
627 - * even after its mask bit is cleared, because signal_pending stays
628 - * 0 and the post-trap process_pending_signals() loop never enters.
629 - */
630 - block_signals();
643 set_sigmask(&set);
644 }
645 env->pc = pc;