Skip to content

Commit 9580d7f

Browse files
committed
Cygwin: thread: Fix stack alignment for PTHREAD_CANCEL_ASYNCHRONOUS
The test case winsup/testsuites/winsup.api/pthread/cancel2 fails on Windows 11 and Windows Server 2025, while it works on Windows 10 and Windows Server 2022. PTHREAD_CANCEL_ASYNCHRONOUS is implemented by forcing the target thread's instruction pointer (IP) to pthread:: static_cancel_self() using [GS]etThreadContext(). static_cancel_self() will call Windows API function during thread shutdown. A misaligned stack will lead to unexpected exceptions. Previously, the stack pointer was not maintained to 16-byte alignment, even though this is required by 64-bit Windows ABI. At the start of the function prologue, the stack is expected to be at an offset of 8 byte from 16-byte boundary (SP % 16 == 8) in x86_64 architecture, as the call instruction has just pushed the return IP onto the stack. However, this appears to have been overlooked when cygwin first added x86_64 support. This patch fixes this issue by aligning the stack pointer as well as the instruction pointer in the PTHREAD_CANCEL_ASYNCHRONOUS handling. Addresses: https://cygwin.com/pipermail/cygwin/2025-December/259117.html Fixes: 6152219 ("* Merge in cygwin-64bit-branch.") Reported-by: Takashi Yano <takashi.yano@nifty.ne.jp> Reviewed-by: Jon Turney <jon.turney@dronecode.org.uk> Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp> (cherry picked from commit b41e3b6)
1 parent ac07897 commit 9580d7f

1 file changed

Lines changed: 20 additions & 0 deletions

File tree

winsup/cygwin/thread.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,27 @@ pthread::cancel ()
629629
threadlist_t *tl_entry = cygheap->find_tls (cygtls);
630630
if (!cygtls->inside_kernel (&context))
631631
{
632+
#if defined(__x86_64__)
633+
/* Need to maintain the alignment of the stack pointer.
634+
https://learn.microsoft.com/en-us/cpp/build/stack-usage?view=msvc-170
635+
states,
636+
"The stack will always be maintained 16-byte aligned,
637+
except within the prolog (for example, after the return
638+
address is pushed),",
639+
that is, we need 16n + 8 byte alignment here because the stack
640+
pointer must be maintaiined to the same alignment required by
641+
the function prologue. Since the call instruction pushes the
642+
return address (rip) onto the stack, which is 8 bytes,
643+
an additional 8 bytes is required to emulate this behaviour.
644+
However, we do not need to push return address itself, because
645+
pthread::static_cancel_self() must not return. */
646+
context.Rsp &= ~0x07UL;
647+
if ((context.Rsp & 8) == 0)
648+
context.Rsp -= 8;
632649
context.Rip = (ULONG_PTR) pthread::static_cancel_self;
650+
#else
651+
#error unimplemented for this target
652+
#endif
633653
SetThreadContext (win32_obj_id, &context);
634654
}
635655
cygheap->unlock_tls (tl_entry);

0 commit comments

Comments
 (0)