Hello,

I was debugging one of my own beginthreadex & floating point test why it
is crashing on 32-bit x86 when executing floating point operation and I
have figured out that it is because of unaligned SSE2 instructions. It
was quite hard to figure it out when I was modifying test for floating
point exceptions and I got some other exception that I was expected.

Basically WinAPI or CRT functions on 32-bit x86 can call callback passed
from gcc/mingw-w64 without prepared stack for SSE2 execution.

To avoid any crashing issues, it is really needed to align stack for
SSE2 execution inside any callback function passed to the WinAPI or CRT
via the __attribute__((force_align_arg_pointer)). mingw-w64 already have
this attribute declared on more callback places but there are still few
missing. In attachment I'm sending changes which adds it. Kirill Makurin
run CI testing for me and all of them passed:
https://github.com/maiddaisuki/mingw-w64/actions/runs/25266565815

Pali
>From 9627843b900ccc444050d243a1d325328abc92f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]>
Date: Sun, 22 Feb 2026 20:13:01 +0100
Subject: [PATCH 1/3] winpthreads: Use force_align_arg_pointer attribute for
 entry point passed to _beginthreadex() for i386 gcc builds

---
 mingw-w64-libraries/winpthreads/tests/clock/t_nanosleep.c   | 6 ++++++
 .../winpthreads/tests/pthread_cancel/cancel7.c              | 6 ++++++
 .../winpthreads/tests/pthread_cancel/cancel8.c              | 6 ++++++
 mingw-w64-libraries/winpthreads/tests/pthread_exit/exit4.c  | 6 ++++++
 mingw-w64-libraries/winpthreads/tests/pthread_exit/exit5.c  | 6 ++++++
 5 files changed, 30 insertions(+)

diff --git a/mingw-w64-libraries/winpthreads/tests/clock/t_nanosleep.c 
b/mingw-w64-libraries/winpthreads/tests/clock/t_nanosleep.c
index c876dc7b0a7c..001bb2c5b1b2 100644
--- a/mingw-w64-libraries/winpthreads/tests/clock/t_nanosleep.c
+++ b/mingw-w64-libraries/winpthreads/tests/clock/t_nanosleep.c
@@ -15,6 +15,12 @@ __int64 timespec_diff_as_ms(struct timespec *__old, struct 
timespec *__new)
          + (__new->tv_nsec - __old->tv_nsec) / POW10_6;
 }
 
+#if defined(__i386__)
+/* Align ESP on 16-byte boundaries. */
+#  if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ 
>= 2))
+__attribute__((force_align_arg_pointer))
+#  endif
+#endif
 unsigned __stdcall start_address(void *dummy)
 {
     int counter = 0;
diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel7.c 
b/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel7.c
index 27c12afb74fe..494432057caa 100644
--- a/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel7.c
+++ b/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel7.c
@@ -95,6 +95,12 @@ struct bag_t_ {
 
 static bag_t threadbag[NUMTHREADS + 1];
 
+#if defined(__i386__)
+/* Align ESP on 16-byte boundaries. */
+#  if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ 
>= 2))
+__attribute__((force_align_arg_pointer))
+#  endif
+#endif
 unsigned int __stdcall
 Win32thread(void * arg)
 {
diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel8.c 
b/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel8.c
index faf28f1e73ed..9972f33c624d 100644
--- a/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel8.c
+++ b/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel8.c
@@ -32,6 +32,12 @@ static void wrap_pthread_mutex_unlock (void *ptr)
   pthread_mutex_unlock ((pthread_mutex_t *) ptr);
 }
 
+#if defined(__i386__)
+/* Align ESP on 16-byte boundaries. */
+#  if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ 
>= 2))
+__attribute__((force_align_arg_pointer))
+#  endif
+#endif
 unsigned int __stdcall
 Win32thread(void * arg)
 {
diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit4.c 
b/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit4.c
index aa377dc94135..4c92660dbe4a 100644
--- a/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit4.c
+++ b/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit4.c
@@ -94,6 +94,12 @@ struct bag_t_ {
 
 static bag_t threadbag[NUMTHREADS + 1];
 
+#if defined(__i386__)
+/* Align ESP on 16-byte boundaries. */
+#  if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ 
>= 2))
+__attribute__((force_align_arg_pointer))
+#  endif
+#endif
 unsigned int __stdcall
 Win32thread(void * arg)
 {
diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit5.c 
b/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit5.c
index bb07ef4fa663..2153f49fa75b 100644
--- a/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit5.c
+++ b/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit5.c
@@ -95,6 +95,12 @@ struct bag_t_ {
 
 static bag_t threadbag[NUMTHREADS + 1];
 
+#if defined(__i386__)
+/* Align ESP on 16-byte boundaries. */
+#  if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ 
>= 2))
+__attribute__((force_align_arg_pointer))
+#  endif
+#endif
 unsigned int __stdcall
 Win32thread(void * arg)
 {
-- 
2.20.1


>From 38754bd17fd88f92313cf38886edf610c20b49e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]>
Date: Sun, 22 Feb 2026 21:14:11 +0100
Subject: [PATCH 2/3] crt: Mark profil profthr_func as force_align_arg_pointer

---
 mingw-w64-crt/profile/profil.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/mingw-w64-crt/profile/profil.c b/mingw-w64-crt/profile/profil.c
index c566bb6dd98d..d03018a36ec9 100644
--- a/mingw-w64-crt/profile/profil.c
+++ b/mingw-w64-crt/profile/profil.c
@@ -72,6 +72,10 @@ print_prof (struct profinfo *p)
 
 static DWORD CALLBACK profthr_func (LPVOID);
 
+#if defined(__i386__)
+/* We need to make sure that we align the stack to 16 bytes for the sake of 
SSE */
+__attribute__((force_align_arg_pointer))
+#endif
 static DWORD CALLBACK
 profthr_func (LPVOID arg)
 {
-- 
2.20.1


>From 746b8e247118d2ce74cd6df64c2b0a08937c242d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]>
Date: Sun, 22 Feb 2026 21:14:42 +0100
Subject: [PATCH 3/3] crt: test: Mark thread_main entry point as
 force_align_arg_pointer

---
 mingw-w64-crt/testcases/t_safe_flush.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/mingw-w64-crt/testcases/t_safe_flush.c 
b/mingw-w64-crt/testcases/t_safe_flush.c
index 7f63dd900870..8c323e8b924a 100644
--- a/mingw-w64-crt/testcases/t_safe_flush.c
+++ b/mingw-w64-crt/testcases/t_safe_flush.c
@@ -15,6 +15,10 @@
 
 CRITICAL_SECTION cs;
 
+#if defined(__i386__)
+/* We need to make sure that we align the stack to 16 bytes for the sake of 
SSE */
+__attribute__((force_align_arg_pointer))
+#endif
 static DWORD WINAPI thread_main(LPVOID user_data) {
     HANDLE handle_event = (HANDLE) user_data;
 
-- 
2.20.1

_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to