For the "[PATCH 3/3] crt: improve _wassert() emulation" I would propose
small improvement (changes attached). It implements decision based on
_set_error_mode() (as it was already written in the comment), use alloca
instead of _alloca (alloca is GNU name and mingw-w64 crt already uses
the non-underscore variant) and reduce calculation of alloca buffers.
Currently it first tries to estimate buffer size based on wcsnlen and
MB_LEN_MAX. Then it calculates the real buffer size correctly via
WideCharToMultiByte() and third time it is using WideCharToMultiByte()
for the final conversion. So the first step via wcsnlen and MB_LEN_MAX
is not needed, the real size can be calculated directly. Also memset is
not needed.
>From 12b499fcbab58c327389ac1869c4a7370a438984 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]>
Date: Tue, 3 Sep 2024 21:00:27 +0200
Subject: [PATCH 1/2] crt: Provide _set_error_mode() function for pre-msvcrt40
 builds

pre-msvcrt40 libraries always print assert error message to stderr
independently of what was set via __set_app_type() call.
---
 mingw-w64-crt/Makefile.am            |  1 +
 mingw-w64-crt/misc/_set_error_mode.c | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+)
 create mode 100644 mingw-w64-crt/misc/_set_error_mode.c

diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index b651dce59d51..9c0d7d1f2d63 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -919,6 +919,7 @@ src_pre_msvcrt40=\
   misc/__dstbias.c \
   misc/__set_app_type.c \
   misc/_dstbias.c \
+  misc/_set_error_mode.c \
   misc/dummy__setusermatherr.c \
   stdio/_filelengthi64.c \
   stdio/_findfirst32i64.c \
diff --git a/mingw-w64-crt/misc/_set_error_mode.c 
b/mingw-w64-crt/misc/_set_error_mode.c
new file mode 100644
index 000000000000..64586cb66ef9
--- /dev/null
+++ b/mingw-w64-crt/misc/_set_error_mode.c
@@ -0,0 +1,26 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#include <stdlib.h>
+
+int __cdecl _set_error_mode(int mode_val)
+{
+  /* Dummy implementation for pre-msvcrt40 builds where assert() always sends
+   * error message to stderr independently of what was set via 
__set_app_type().
+   * No change in this behavior is possible, so just validate input argument 
and
+   * always return _OUT_TO_STDERR or -1.
+   */
+  switch (mode_val) {
+    case _OUT_TO_DEFAULT:
+    case _OUT_TO_STDERR:
+    case _OUT_TO_MSGBOX:
+    case _REPORT_ERRMODE:
+      return _OUT_TO_STDERR;
+    default:
+      return -1;
+  }
+}
+int (__cdecl *__MINGW_IMP_SYMBOL(_set_error_mode))(int) = _set_error_mode;
-- 
2.20.1


>From 9066ff3585caa18f3eb5e3b7bef08c889f163f85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]>
Date: Sat, 20 Jun 2026 22:26:51 +0200
Subject: [PATCH 2/2] fixup! crt: improve _wassert() emulation

---
 mingw-w64-crt/misc/wassert.c | 78 ++++++++++++++++--------------------
 1 file changed, 35 insertions(+), 43 deletions(-)

diff --git a/mingw-w64-crt/misc/wassert.c b/mingw-w64-crt/misc/wassert.c
index 9faaa4ba4958..2ad741191925 100644
--- a/mingw-w64-crt/misc/wassert.c
+++ b/mingw-w64-crt/misc/wassert.c
@@ -5,15 +5,15 @@
  */
 
 #include <assert.h>
-#include <limits.h>
+#include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
 
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
+extern int __mingw_app_type; /* filled by crtexe.c and crtdll.c */
+
 /**
  * Convert wide character string `wcs` to code page `cp`.
  *
@@ -30,17 +30,23 @@ static void conv (char *buffer, int buffer_size, const 
wchar_t *wcs, unsigned cp
      *
      * This allows us to preserve and display as much information as possible.
      */
-    int length = WideCharToMultiByte (cp, 0, wcs, -1, NULL, 0, NULL, NULL);
-
-    if (length == 0) {
-        return;
-    }
-
-    if (length > buffer_size) {
-        buffer_size -= 1;
-    }
+    int length = WideCharToMultiByte (cp, 0, wcs, -1, buffer, buffer_size, 
NULL, NULL);
+    if (length <= 0)
+        buffer[0] = '\0';
+    else if (length >= buffer_size)
+        buffer[buffer_size-1] = '\0';
+    else
+        buffer[length-1] = '\0';
+}
 
-    WideCharToMultiByte (cp, 0, wcs, -1, buffer, buffer_size, NULL, NULL);
+static int convsize (int max_buffer_size, const wchar_t *wcs, unsigned cp) {
+    int length = WideCharToMultiByte (cp, 0, wcs, -1, NULL, 0, NULL, NULL);
+    if (length <= 0)
+        return 1; /* 1 for nul term */
+    else if (length >= max_buffer_size)
+        return max_buffer_size;
+    else
+        return length + 1; /* +1 for nul term */
 }
 
 /* _wassert is not available on XP, so forward it to _assert if needed */
@@ -60,27 +66,7 @@ static void __cdecl emu__wassert(const wchar_t *_Message, 
const wchar_t *_File,
      *
      * As the result, we should avoid using static buffer to avoid race
      * condition when multiple threads call _wassert() at the same time.
-     */
-    char *message = NULL;
-    char *file = NULL;
-
-    /**
-     * Estimate maximum buffer size assuming that each wide character converts
-     * to at least 1 byte and at most `MB_LEN_MAX` bytes.
-     */
-    int message_length = wcsnlen (_Message, BUFSIZ) * MB_LEN_MAX;
-    int file_length = wcsnlen (_File, FILENAME_MAX) * MB_LEN_MAX;
-
-    message_length = __min (message_length, BUFSIZ);
-    file_length = __min (file_length, FILENAME_MAX);
-
-    message = _alloca (message_length);
-    file = _alloca (file_length);
-
-    memset (message, 0, message_length);
-    memset (file, 0, file_length);
-
-    /**
+     *
      * _assert() prints `_Message` to stderr or displays a message box,
      * depending on _set_error_mode setting.
      *
@@ -90,17 +76,23 @@ static void __cdecl emu__wassert(const wchar_t *_Message, 
const wchar_t *_File,
      * When displaying a message box, we want to convert `_Message` to active
      * ANSI code page; most ANSI APIs interpret strings using that code page.
      *
-     * Perfectly, we would call _set_error_mode (_REPORT_ERRMODE) to query
-     * current setting and decide which code page to use; we cannot do this
-     * because _set_error_mode is not available in crtdll.dll, msvcrt10.dll and
-     * msvcrt20.dll.
-     *
-     * Use active ANSI code page as the conservative option.
      */
-    unsigned cp = GetACP ();
 
-    conv (message, message_length, _Message, cp);
-    conv (file, file_length, _File, cp);
+    unsigned cp;
+    int errmode = _set_error_mode (_REPORT_ERRMODE);
+    if (errmode == _OUT_TO_STDERR || (errmode == _OUT_TO_DEFAULT && 
__mingw_app_type == 0 /*console*/))
+        cp = ___lc_codepage_func (); /* stderr codepage */
+    else
+        cp = GetACP (); /* gui MessageBoxA codepage */
+
+    int message_size = convsize (BUFSIZ, _Message, cp);
+    int file_size = convsize (FILENAME_MAX, _File, cp);
+
+    char *message = alloca (message_size);
+    char *file = alloca (file_size);
+
+    conv (message, message_size, _Message, cp);
+    conv (file, file_size, _File, cp);
 
     _assert(message, file, _Line);
 }
-- 
2.20.1

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

Reply via email to