Commit e0f0ce88eb for qemu.org

commit e0f0ce88eb9e526cf8271f124478143fc3ae388a
Author: Matt Turner <mattst88@gmail.com>
Date:   Wed Jun 3 12:18:51 2026 -0400

    linux-user/sparc: call block_signals() before set_sigmask() in setcontext

    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 <mattst88@gmail.com>
    Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
    Signed-off-by: Helge Deller <deller@gmx.de>

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);
     }
     env->pc = pc;