If the signal handler is called from inside of another signal handler,
_cygtls::context may be destroyed by call_signal_handler() newly called.
To avoid this situation, this patch used context locally copied in
call_signal_handler().

Addresses: https://cygwin.com/pipermail/cygwin-patches/2025q1/013461.html
Fixes: 9043956ce859 ("Only construct ucontext for SA_SIGINFO signal handlers")
Reported-by: Takashi Yano <takashi.y...@nifty.ne.jp>
Reviewed-by:
Signed-off-by: Takashi Yano <takashi.y...@nifty.ne.jp>
---
 winsup/cygwin/exceptions.cc | 41 ++++++++++++++++++++-----------------
 1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 18a566c45..1e19af68c 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -1660,6 +1660,8 @@ altstack_wrapper (int sig, siginfo_t *siginfo, ucontext_t 
*sigctx,
 int
 _cygtls::call_signal_handler ()
 {
+  ucontext_t context1 = context;
+
   int this_sa_flags = SA_RESTART;
   while (1)
     {
@@ -1697,10 +1699,10 @@ _cygtls::call_signal_handler ()
       /* Only make a context for SA_SIGINFO handlers */
       if (this_sa_flags & SA_SIGINFO)
        {
-         context.uc_link = 0;
-         context.uc_flags = 0;
+         context1.uc_link = 0;
+         context1.uc_flags = 0;
          if (thissi.si_cyg)
-           memcpy (&context.uc_mcontext,
+           memcpy (&context1.uc_mcontext,
                    ((cygwin_exception *) thissi.si_cyg)->context (),
                    sizeof (CONTEXT));
          else
@@ -1710,13 +1712,13 @@ _cygtls::call_signal_handler ()
                 from sigdelayed, fix the instruction pointer accordingly. */
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-             RtlCaptureContext ((PCONTEXT) &context.uc_mcontext);
+             RtlCaptureContext ((PCONTEXT) &context1.uc_mcontext);
 #pragma GCC diagnostic pop
-             __unwind_single_frame ((PCONTEXT) &context.uc_mcontext);
+             __unwind_single_frame ((PCONTEXT) &context1.uc_mcontext);
              if (stackptr > stack)
                {
 #ifdef __x86_64__
-                 context.uc_mcontext.rip = retaddr ();
+                 context1.uc_mcontext.rip = retaddr ();
 #else
 #error unimplemented for this target
 #endif
@@ -1727,30 +1729,30 @@ _cygtls::call_signal_handler ()
              && !_my_tls.altstack.ss_flags
              && _my_tls.altstack.ss_sp)
            {
-             context.uc_stack = _my_tls.altstack;
-             context.uc_stack.ss_flags = SS_ONSTACK;
+             context1.uc_stack = _my_tls.altstack;
+             context1.uc_stack.ss_flags = SS_ONSTACK;
            }
          else
            {
-             context.uc_stack.ss_sp = NtCurrentTeb ()->Tib.StackBase;
-             context.uc_stack.ss_flags = 0;
+             context1.uc_stack.ss_sp = NtCurrentTeb ()->Tib.StackBase;
+             context1.uc_stack.ss_flags = 0;
              if (!NtCurrentTeb ()->DeallocationStack)
-               context.uc_stack.ss_size
+               context1.uc_stack.ss_size
                  = (uintptr_t) NtCurrentTeb ()->Tib.StackLimit
                    - (uintptr_t) NtCurrentTeb ()->Tib.StackBase;
              else
-               context.uc_stack.ss_size
+               context1.uc_stack.ss_size
                  = (uintptr_t) NtCurrentTeb ()->DeallocationStack
                    - (uintptr_t) NtCurrentTeb ()->Tib.StackBase;
            }
-         context.uc_sigmask = context.uc_mcontext.oldmask = this_oldmask;
+         context1.uc_sigmask = context1.uc_mcontext.oldmask = this_oldmask;
 
-         context.uc_mcontext.cr2 = (thissi.si_signo == SIGSEGV
-                                    || thissi.si_signo == SIGBUS)
-                                   ? (uintptr_t) thissi.si_addr : 0;
+         context1.uc_mcontext.cr2 = (thissi.si_signo == SIGSEGV
+                                     || thissi.si_signo == SIGBUS)
+                                    ? (uintptr_t) thissi.si_addr : 0;
 
-         thiscontext = &context;
-         context_copy = context;
+         thiscontext = &context1;
+         context_copy = context1;
        }
 
       int this_errno = saved_errno;
@@ -1836,10 +1838,11 @@ _cygtls::call_signal_handler ()
       incyg = true;
 
       set_signal_mask (_my_tls.sigmask, (this_sa_flags & SA_SIGINFO)
-                                       ? context.uc_sigmask : this_oldmask);
+                                       ? context1.uc_sigmask : this_oldmask);
       if (this_errno >= 0)
        set_errno (this_errno);
     }
+  context = context1;
 
   /* FIXME: Since 2011 this return statement always returned 1 (meaning
      SA_RESTART is effective) if the thread we're running in is not the
-- 
2.45.1

Reply via email to