On Wed, 10 Jun 2026 at 17:46, Helge Deller <[email protected]> wrote: > > From: Matt Turner <[email protected]> > > sparc64_set_context() emulates the kernel's `ta 0x6f` trap by calling > set_sigmask() to install the mask supplied via the user's ucontext_t. > The contract of set_sigmask() (see its comment in linux-user/signal.c) > is that the caller must have first called block_signals(), which sets > TaskState::signal_pending. > > Without block_signals(), if a guest signal is pending-and-blocked at > the time setcontext is invoked and the new mask unblocks it, > signal_pending stays 0 and the post-trap process_pending_signals() > call in linux-user/sparc/cpu_loop.c never enters its while loop, so > the now-deliverable signal is left undelivered indefinitely. > > This affects programs that use getcontext/setcontext to swap signal > masks, including libunwind's unw_resume() out of a signal handler: > without this fix, the test program below loops forever printing > "calling setcontext" instead of delivering the pending SIGUSR2. > > #define _GNU_SOURCE > #include <ucontext.h> > #include <signal.h> > #include <stdio.h> > #include <unistd.h> > static int got; > static void h(int s) { got = 1; } > int main(void) { > signal(SIGUSR2, h); > sigset_t m; sigemptyset(&m); sigaddset(&m, SIGUSR2); > sigprocmask(SIG_BLOCK, &m, NULL); > kill(getpid(), SIGUSR2); > ucontext_t uc; > getcontext(&uc); > if (got) return 0; > uc.uc_sigmask.__val[0] = 0; > setcontext(&uc); > return 1; > } > > The 32-bit sparc do_sigreturn / do_rt_sigreturn paths already get > block_signals() from the rt_sigreturn syscall wrapper in > linux-user/syscall.c, so only sparc64_set_context (invoked directly > from cpu_loop) needs the addition. > > Signed-off-by: Matt Turner <[email protected]> > Cc: Mark Cave-Ayland <[email protected]> > Signed-off-by: Helge Deller <[email protected]> > --- > linux-user/sparc/signal.c | 9 +++++++++ > 1 file changed, 9 insertions(+) > > diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c > index fda5508c48..ba692c3123 100644 > --- a/linux-user/sparc/signal.c > +++ b/linux-user/sparc/signal.c > @@ -619,6 +619,15 @@ void sparc64_set_context(CPUSPARCState *env) > } > } > target_to_host_sigset_internal(&set, &target_set); > + /* > + * set_sigmask() requires the caller to have first called > + * block_signals() so that process_pending_signals() is guaranteed > + * to run after the mask change. Without this, a guest signal that > + * is pending-and-blocked at setcontext time is left undelivered > + * even after its mask bit is cleared, because signal_pending stays > + * 0 and the post-trap process_pending_signals() loop never enters. > + */ > + block_signals(); > set_sigmask(&set);
Hi; Coverity points out (CID 1660058) that every other callsite of block_signals() checks its return value and does something if it returns non-zero (indicating that a signal is pending and typically that we should return -TARGET_ERESTARTSYS to take the pending signal). Is it OK to ignore the return value here? If so, saying why in the comment would probably be useful. thanks -- PMM
