https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=156aa34b32e469f8dafee0c85667b3cab1b5c598

commit 156aa34b32e469f8dafee0c85667b3cab1b5c598
Author: Takashi Yano <takashi.y...@nifty.ne.jp>
Date:   Wed May 28 13:47:46 2025 +0900

    Cygwin: signal: Prevent unexpected crash on frequent SIGSEGV
    
    When the thread is suspended and Rip (instruction pointer) points to
    an instruction that causes an exception, modifying Rip and calling
    ResumeThread() may sometimes result in a crash. To prevent this,
    advance execution by a single instruction by setting the trap flag
    (TF) before calling ResumeThread() as a workaround. This will trigger
    either STATUS_SINGLE_STEP or the exception caused by the instruction
    that Rip originally pointed to. By suspending the targeted thread
    within exception::handle(), Rip no longer points to the problematic
    instruction, allowing safe handling of the interrupt. As a result,
    Rip can be adjusted appropriately, and the thread can resume
    execution without unexpected crashes.
    
    Addresses: https://cygwin.com/pipermail/cygwin/2025-May/258153.html
    Fixes: 1fd5e000ace5 ("import winsup-2000-02-17 snapshot")
    Reported-by: Christian Franke <christian.fra...@t-online.de>
    Reviewed-by: Corinna Vinschen <cori...@vinschen.de>
    Signed-off-by: Takashi Yano <takashi.y...@nifty.ne.jp>
    (cherry picked from commit f305ca916ad25870fb010334e4fcaf93057c78b9)

Diff:
---
 winsup/cygwin/exceptions.cc           | 37 +++++++++++++++++++++++++++++++++++
 winsup/cygwin/local_includes/cygtls.h |  1 +
 winsup/cygwin/local_includes/ntdll.h  |  3 ++-
 winsup/cygwin/release/3.6.4           |  5 +++++
 4 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 876b79e36..804adc92b 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -653,6 +653,13 @@ exception::handle (EXCEPTION_RECORD *e, exception_list 
*frame, CONTEXT *in,
   static int NO_COPY debugging = 0;
   _cygtls& me = _my_tls;
 
+  if (me.suspend_on_exception)
+    {
+      SuspendThread (GetCurrentThread ());
+      if (e->ExceptionCode == (DWORD) STATUS_SINGLE_STEP)
+       return ExceptionContinueExecution;
+    }
+
   if (debugging && ++debugging < 500000)
     {
       SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL);
@@ -929,6 +936,36 @@ _cygtls::interrupt_now (CONTEXT *cx, siginfo_t& si, void 
*handler,
     interrupted = false;
   else
     {
+#ifdef __x86_64__
+      /* When the Rip points to an instruction that causes an exception,
+        modifying Rip and calling ResumeThread() may sometimes result in
+        a crash. To prevent this, advance execution by a single instruction
+        by setting the trap flag (TF) before calling ResumeThread(). This
+        will trigger either STATUS_SINGLE_STEP or the exception caused by
+        the instruction that Rip originally pointed to.  By suspending the
+        targeted thread within exception::handle(), Rip no longer points
+        to the problematic instruction, allowing safe handling of the
+        interrupt. As a result, Rip can be adjusted appropriately, and the
+        thread can resume execution without unexpected crashes.  */
+      if (!inside_kernel (cx, true))
+       {
+         cx->EFlags |= 0x100; /* Set TF (setup single step execution) */
+         SetThreadContext (*this, cx);
+         suspend_on_exception = true;
+         ResumeThread (*this);
+         ULONG cnt = 0;
+         NTSTATUS status;
+         do
+           {
+             yield ();
+             status = NtQueryInformationThread (*this, ThreadSuspendCount,
+                                                &cnt, sizeof (cnt), NULL);
+           }
+         while (NT_SUCCESS (status) && cnt == 0);
+         GetThreadContext (*this, cx);
+         suspend_on_exception = false;
+       }
+#endif
       DWORD64 &ip = cx->_CX_instPtr;
       push (ip);
       interrupt_setup (si, handler, siga);
diff --git a/winsup/cygwin/local_includes/cygtls.h 
b/winsup/cygwin/local_includes/cygtls.h
index 4698352ae..1b3bf65f1 100644
--- a/winsup/cygwin/local_includes/cygtls.h
+++ b/winsup/cygwin/local_includes/cygtls.h
@@ -203,6 +203,7 @@ public: /* Do NOT remove this public: line, it's a marker 
for gentls_offsets. */
   __tlsstack_t *stackptr;
   __tlsstack_t stack[TLS_STACK_SIZE];
   unsigned initialized;
+  volatile bool suspend_on_exception;
 
 public: /* Do NOT remove this public: line, it's a marker for gentls_offsets. 
*/
   void init_thread (void *, DWORD (*) (void *, void *));
diff --git a/winsup/cygwin/local_includes/ntdll.h 
b/winsup/cygwin/local_includes/ntdll.h
index 299167217..242a6a64b 100644
--- a/winsup/cygwin/local_includes/ntdll.h
+++ b/winsup/cygwin/local_includes/ntdll.h
@@ -1365,7 +1365,8 @@ typedef enum _THREADINFOCLASS
   ThreadBasicInformation = 0,
   ThreadTimes = 1,
   ThreadImpersonationToken = 5,
-  ThreadQuerySetWin32StartAddress = 9
+  ThreadQuerySetWin32StartAddress = 9,
+  ThreadSuspendCount = 35
 } THREADINFOCLASS, *PTHREADINFOCLASS;
 
 typedef struct _THREAD_BASIC_INFORMATION
diff --git a/winsup/cygwin/release/3.6.4 b/winsup/cygwin/release/3.6.4
new file mode 100644
index 000000000..ef3aec68e
--- /dev/null
+++ b/winsup/cygwin/release/3.6.4
@@ -0,0 +1,5 @@
+Fixes:
+------
+
+- Fix unexpected crash when SIGSEGV occurs too frequently.
+  Addresses: https://cygwin.com/pipermail/cygwin/2025-May/258153.html

Reply via email to