Hello,

I looked at these issues. And basically there are 3 things which could
be done independently.

1. Decide whether C assert() macro would respect _UNICODE and use CRT
_assert() or CRT _wassert() function. Or if it would not respect
_UNICODE and always forces usage of UTF-16 _wassert() variant.

2. Fixing of mingw-w64 _assert() function. Or removal of mingw-w64
_assert() implementation and let to use just broken DLL implementation.

3. Changing/Fixing of the mingw-w64 _wassert() emulation.


About application usage. I think it is not important if the recent MS
doc say that some function (e.g. _assert()) should not be used by
application or not. Application would always use functions which are
available and are part of CRT DLL ABI. Saying "do not use" or forcing by
"removal of symbol" would just cause breaking.

Also I think that it is not important of usage of function, macro,
parameter flag, enum, whatever... is going to be forbidden in header
file or not. Lot of times I saw that applications are doing thing like
"#ifndef FLAG\n#define FLAG ...\n#endif" with comment that some older
SDK or broken SDK do not provide FLAG. And personally I also did it lot
of times when I figured out that FLAG was not exported.

So the "Expose _O_{W,U16,U8}TEXT macros only for CRTs..." part is not a
good idea as described above. At least this is what I think.

Also important is that mingw-w64 header files are for C and C++
languages but there are usage also for other languages, which directly
uses mingw-w64-crt libraries. My feeling is that separation of
mingw-w64-crt and mingw-w64-headers is a good idea to show what is
provided for linker and what is provided for C/C++ language.


Now about 1. forward C assert() macro to CRT _wassert() function. I have
subjective preference to not do it. I understand concerns and I right
now I do not see any good solution. My feeling is that both are bad.
I'm looking at this from direction: I explicitly did not set _UNICODE
so I want from my application (which includes mingw-w64 header files) to
not emit _UNICODE/UTF-16 symbols, for example for compatibility with
non-UNICODE systems. MS is for a longer time trying to convince
developers to use UNICODE/UTF-16 functions and entry points and the
change which switched assert to _wassert in MS header files was done
long time ago (when they completely dropped Win9x support). But now I
think that direction is moving from UTF-16 to UTF-8. I know this is not
very good argument, just my subjective preference. On the other hand,
issues which you pointed out are valid which should be solved. And if
there is no other option how to solve those issues then probably the
switch is the direction. But before that I would like to try fixing
other options.

Also I do not like the fact that the assert() macro would be forwarded
to _wassert() function, which for older libs would be emulated by
mingw-w64 which at the end would call _assert() by doing reallocations
and conversions back and forward.


About 2. removal vs fix of mingw-w64 _assert() function. If switch in 1.
would happen then I think there is no reason to remove _assert() and I
would like to try to fix it, not remove.

About 3. fixing of _wassert() emulation. This emulation always uses the
_assert() function for its implementation. Hence if the _assert stays
broken then the _wassert() emulation would be also always broken,
whatever would be done.

So I would take 2. + 3. together and my ideas are:

- _set_error_mode is not available in crtdll.dll, msvcrt10.dll and
  msvcrt20.dll CRT libs; but this is not a problem, I can provide
  working "emulation" of this function which would return correct value
  for _set_error_mode (_REPORT_ERRMODE) call. This is because these
  libraries always prints message to stderr via fprintf; not to GUI.

- about cleaning resources if the _(w)assert returns back. I would
  propose to use SEH unwind handler to do it. I have already looked at
  SEH deeply and we can do it. Also longjmp _by default_ on ms builds is
  calling the unwind handler, so I think it would be a good idea to do
  it also in mingw-w64.

- malloc vs static buffer vs _alloca. Usage of _alloca or variable
  length arrays are mostly means issues in code. And having them in
  "assert" implementation (which is called by application then something
  bad happens) sounds like a trouble. Specially if compiler generates
  code for stack overflow protection for any alloca/VLA usage and calls
  assert if overflow happens. We could have potentially new issues.
  I'm not sure if compilers are doing this now, but I can imagine that
  this is a valid thing to do.
  But with static buffers I understand issue that multiple threads
  cannot at the same time call assert. And when starting to use signal
  handlers, then issue can happen even with one thread when signal
  handler calls assert with a new signal handler and both would want to
  longjump from it based on some condition. In this case the assert
  temporary buffer would be used just by one thread, but by two
  different callers intermixed. So even possible thread local buffer
  would not help here.

- usage of GetACP() for codepage. It is wrong like usage of any other
  option. When printing to console, it is needed to use function
  GetConsoleOutputCP().

- problem with encoding comes from the fact that _compiler_ fills the
  assert message in its own encoding. But at the same time the _assert
  function (provided by DLL) has some encoding contract (with bugs...)
  how it should be called. So I have feeling that here we are mixing
  more separate issues into one functionality and that is why it is in
  this bad shape. gcc has -finput-charset=charset and
  -fexec-charset=charset options (and maybe some other internal options)
  which if I understand correctly can affect the asserted message which
  is then expanded into _assert call. Should not we rather have separate
  mingw-w64 function e.g. _assert_called_from_gcc_option1 (or whatever)
  and then CRT _assert function which is according to the ABI?
  Because my feeling is that "assert" is a C macro mostly tied with
  compiler nad "_assert" is MS CRT function which follows some ABI and
  these two things needs some layer to be correctly connected. Here we
  are trying to change "_assert" which looks to be wrong. For example
  some other compiler/language can use "_assert" function directly if it
  is not C/C++.

About your last point C. We can check if the current symbol for e.g.
_assert points to msvcrt.dll or to some other library. And this check
can be in the per-CRT library. This should work correctly as forward are
done at PE loader level. And it will sets symbol to point to different
library. I think that if it is done in this way it should not have a
problem. The point is to not use GetProcAddress, but rather to figure
out HMODULE directly from __imp_<symbol> pointer at runtime. And I think
that in the same way could be implemented _set_error_mode (_REPORT_ERRMODE)
call to work reliable in case crtdll.dll/msvcrt20.dll (w)print functions
are redirected to msvcrt.dll.


I would like to try to implement alternative solution to these issues.
Maybe I will figure out that it is not possible, and your change is the
the best what can be done, even it is not ideal. But that is one of
scenarios.


If I understand correctly, right now in the mingw-w64 git code we have
memory leaks in assert and wrong encoding of non-ASCII assert messages
and damaging of _O_WTEXT/_O_U16TEXT/_O_U8TEXT mode in case the assert is
ignored and is going to continue. IMHO all those cases are not the
primary code path, was there a longer time, so should not cause an issue
if these issues would be fixed/merged later and not immediately.

Pali

On Thursday 18 June 2026 12:36:04 Kirill Makurin wrote:
> Hello,
> 
> A few days ago, I sent changes which removed noreturn attribute from 
> `_assert` and `_wassert` functions. After that, I was thinking about wrappers 
> we provide, and I think that they are really problematic. I think those 
> wrappers were initially implemented under assumption that neither `_assert` 
> nor `_wassert` can return.
> 
> Before I start, I want to mention that recent versions of Windows SDK always 
> implement `assert` using `_wassert` and do not even expose `_assert` to the 
> user. In contrast, mingw-w64 uses `_wassert` only when `UNICODE` or 
> `_UNICODE` macros are defined; by default, it uses `_assert`.
> 
> Another thing to keep in mind about both `_[w]assert` functions is that they 
> call `abort` to terminate the process. If application has set a signal 
> handler for SIGABRT, `abort` will invoke that handler before terminating the 
> process. An application can supply SIGABRT handler which calls `longjmp` to 
> continue execution from a save point.
> 
> In wrapper for `_assert`, we change stderr translation mode to `_O_TEXT`, so 
> that CRT `_assert` function can print assertion message using `fprintf` 
> function; otherwise, it would produce no output, and in debug versions of 
> CRT, it would trigger an internal assertion. In case when CRT `_assert` 
> returns, we must restore translation mode used by stderr before the call. 
> However, if application escapes from `_assert` through SIGABRT handler, we 
> will not restore translation mode on stderr, leaving it in a state which may 
> cause application to misbehave.
> 
> Another problem here is that restoration can only occur when `_assert` pops 
> up a message box (so user can press the "Ignore" button), in which case 
> translation mode juggling is not required at all, but we have to do it since 
> we switch it to `_O_TEXT` unconditionally. Currently, we cannot call 
> `_set_error_mode (_REPORT_ERRMODE)` to switch it conditionally because it is 
> not available in crtdll.dll, msvcrt10.dll and msvcrt20.dll.
> 
> In wrapper for `_wassert` we use `malloc` to allocate memory to hold 
> converted strings with fallback to static buffers. Currently, `_wassert` does 
> not free allocated strings. Even if we free allocated memory in case 
> `_assert` returns, application still can use SIGABRT handler to escape from 
> `_assert`, in which case we will end up with a memory leak.
> 
> I propose the following changes to `assert` implementation:
> 
> 1. Always use `_wassert`, which properly works with Unicode translation 
> modes. This function is available in all CRTs which support Unicode 
> translation modes; in case of msvcrt.dll, the wrapper already checks whether 
> it is available in the DLL, and if available, uses it instead of emulation 
> around `_assert`.
> 
> 2. Remove wrapper for `_assert`. The purpose for this wrapper was to make 
> `assert` usable if application set stderr to a Unicode translation mode. If 
> we always use `_wassert`, there is no need for this `_assert` wrapper. Both 
> `_[w]assert` functions are not really supposed to be called directly by 
> applications, and if they do, they must be aware of this limitation.
> 
> 3. Improve `_wassert` emulation by making it thread-safe and improving 
> conversion of its arguments, which are then passed to `_assert`.
> 
> Proposed changes are in attachment. These changes passed CI: 
> https://github.com/maiddaisuki/mingw-w64/actions/runs/27751004928.
> 
> There are, however, a few specific corner cases: crtdll.dll, msvcrt20.dll and 
> msvcrt40.dll. Those CRTs may simply forward to OS msvcrt.dll (crtdll.dll and 
> msvcrt20.dll started forwarding to msvcrt.dll in recent Windows 11 updates), 
> which may allow an appliation to set a stream to a Unicode translation mode, 
> while we keep using `_assert` through `_wassert` emulation.
> 
> What we can do is:
> 
> A. Ignore. Unicode translation modes are not supported by real, standalone 
> versions of crtdll.dll and msvcrt{20,40}.dll.
> 
> B. Expose _O_{W,U16,U8}TEXT macros only for CRTs where there are actually 
> usable, making it impossible to use them in crtdll.dll and msvcrt{20,40}.dll.
> 
> C. Handle it on per-CRT basis, providing a custom check whether msvcrt.dll is 
> loaded and contains `_wassert`. This creates a window for errors, because it 
> is possible that msvcrt.dll was loaded by another DLL, and its internal state 
> has nothing to do with *current* CRT.
> 
> I am in favor of B.
> 
> - Kirill Makurin


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

Reply via email to