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