On Tuesday 16 December 2025 15:05:38 Luca Bacci wrote: > Hi, thanks for your feedback! > > > This doesn't work the way you want; as much as possible of the base files > from mingw-w64-crt are agnostic of the choice of default CRT > > Ah, indeed the same CRT library is used regardless of the -mcrtdll argument > used in GCC. > > > [...] It is calling code outside of __native_startup_state guards. > > Yeah, I am now fixing that patch too! Out of curiosity, what is that lock > used for? I can't quite understand
I'm also not really sure, but from its logic it looks like that it prevents duplicate execution by different threads at the same time. Similar logic has also code generated by msvc compiler. In past I sent some analysis of it into this list. > > Anyway, for such changes it would be very useful to have an automated test > > Ok, done! I have attached the patchset V2. Here are the relevant changes: > > > 1. > Fixed a few typos in the commit message (s/then/than, C23 section is now > correct) > 2. > Fixed indentation > 3. > I now check the return value of setvbuf. Let me know if we can skip that... IMHO, we should skip it. stderr does not have to be available. > 4. > Call to setvbuf has been moved right before the invocation of .CRT$XC > callbacks. IMO that's the right time to make the call I think this is too late. Application code can contain other .CRT callbacks which are called before. Also some functions called by mingw-w64 could in some cases trigger assert which prints to stderr. Should it be called before or after _pei386_runtime_relocator? > 5. > Added a testcase > > Slightly off-topic: the mingw-w64-crt testsuite always links against the > system-provided mingw-w64-crt rather than the built one. Is there any easy > way to change that? You can specify custom CC, CFLAGS and LDFLAGS options when calling "make check" command. > > Thanks, > Luca > > ________________________________ > Da: Pali Rohár <[email protected]> > Inviato: sabato 13 dicembre 2025 20:03 > A: Luca Bacci <[email protected]>; Martin Storsjö <[email protected]> > Cc: Mingw W64 Public <[email protected]> > Oggetto: Re: [Mingw-w64-public] Ensure that stderr is not fully buffered > > On Saturday 13 December 2025 20:38:36 Martin Storsjö wrote: > > On Sat, 13 Dec 2025, Luca Bacci wrote: > > > > > diff --git a/mingw-w64-crt/crt/crtexe.c b/mingw-w64-crt/crt/crtexe.c > > > index 94bad6aa..d7497ef0 100644 > > > --- a/mingw-w64-crt/crt/crtexe.c > > > +++ b/mingw-w64-crt/crt/crtexe.c > > > @@ -199,6 +199,17 @@ __tmainCRTStartup (void) > > > if (__globallocalestatus == -1) > > > _configthreadlocale (-1); > > > > > > +#if !defined (_UCRT) > > > > This doesn't work the way you want; as much as possible of the base files > > from mingw-w64-crt are agnostic of the choice of default CRT. In particular, > > all the files in mingw-w64-crt are built with "-D__MSVCRT_VERSION__=0x600". > > Only the files that go into the individual CRT import libraries can assume > > things about which CRT they're used with. > > > > One way of working around this would be to add a call to a function, which > > in the libmsvcr*.a libraries does what you want, but in libucrt*.a would be > > a dummy no-op function. > > > > Pali may have other suggestions or opinions about how to deal with this. > > > > // Martin > > Yes, ifdef for _UCRT in mingw-w64-crt/* directory does not work, it is > never defined. I would suggest to call setvbuf() unconditionally. That > is simple solution and would work with any CRT library. > > I looked at second change > https://sourceforge.net/p/mingw-w64/mailman/message/59272390/ > and seems that this one is not correct too. It is calling code outside > of __native_startup_state guards. > > Anyway, for such changes it would be very useful to have an automated > test. So we can see what is happening without the change and with the > change. Lot of different tests are in the mingw-w64-crt/testcases/ dir. > For example test t_assert.c is spawning new process and using pipe on > stderr and is checking that stderr was properly transferred. > diff --git a/mingw-w64-crt/testcases/t_stderr_buffering.c > b/mingw-w64-crt/testcases/t_stderr_buffering.c > new file mode 100644 > index 00000000..82938c24 > --- /dev/null > +++ b/mingw-w64-crt/testcases/t_stderr_buffering.c > @@ -0,0 +1,58 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <assert.h> > +#include <process.h> > +#include <io.h> > +#include <fcntl.h> > +#include <windows.h> > + > +#define STRING "hello world!" > + > +int main(int argc, char *argv[]) { > + if (argc != 2 || strcmp(argv[1], "stderr_buffering_test") != 0) { > + int exit_code; > + int pipefd[2]; > + int back_errfd; > + intptr_t process; > + ssize_t size; > + char buf[512]; > + > + assert(_pipe(pipefd, sizeof(buf), _O_NOINHERIT) == 0); > + > + /* set stderr fd to write side of pipe, will be used by _spawnl() */ > + assert((back_errfd = dup(STDERR_FILENO)) >= 0); > + assert(dup2(pipefd[1], STDERR_FILENO) == 0); > + assert(close(pipefd[1]) == 0); > + > + process = _spawnl(_P_NOWAIT, _pgmptr, argv[0], > "stderr_buffering_test", NULL); > + > + /* revert back stderr fd */ > + assert(dup2(back_errfd, STDERR_FILENO) == 0); > + assert(close(back_errfd) == 0); > + > + assert(process != -1); > + > + size = read(pipefd[0], buf, sizeof(buf)); > + close(pipefd[0]); > + > + /* wait until child process exits */ > + assert(_cwait(&exit_code, process, _WAIT_CHILD) == process); > + assert(exit_code == 0); > + > + assert(size > 0); /* some data were written by child process */ > + assert(strncmp(buf, STRING, strlen (STRING)) == 0); > + > + return 0; > + } > + > + /* stderr must not be fully-buffered on startup */ > + fputs(STRING "\n", stderr); Is "\n" needed there? It can cause flush for line-buffered settings. > + assert(!ferror (stderr)); > + > + /* could also use _Exit here... */ > + TerminateProcess(GetCurrentProcess(), 0); > + > + /* unreachable */ > + assert(0); > +} > -- > 2.49.0.windows.1 > > From 0fc043eb79cc55e303509077e07639545ba67a1c Mon Sep 17 00:00:00 2001 > From: Luca Bacci <[email protected]> > Date: Tue, 16 Dec 2025 15:32:03 +0100 > Subject: [PATCH 2/3] crt: Fix comment > > Signed-off-by: Luca Bacci <[email protected]> > --- > mingw-w64-crt/crt/crtexe.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/mingw-w64-crt/crt/crtexe.c b/mingw-w64-crt/crt/crtexe.c > index 94bad6aa..439d1aea 100644 > --- a/mingw-w64-crt/crt/crtexe.c > +++ b/mingw-w64-crt/crt/crtexe.c > @@ -215,8 +215,8 @@ __tmainCRTStartup (void) > if (ret != 0) > _amsg_exit (8); /* _RT_SPACEARG */ > > - _initterm (__xc_a, __xc_z); > - __main (); /* C++ initialization. */ > + _initterm (__xc_a, __xc_z); /* C++ initialization */ > + __main (); Comment was correct. gcc __main function is calling gcc generated c++ constructors (initializations). __xc_a-__xc_z contains only user customer callbacks, not generated by gcc. > > __native_startup_state = __initialized; > } > -- > 2.49.0.windows.1 > > From 80886dc4cdf8295c391eac7fb3ba75af52a1b124 Mon Sep 17 00:00:00 2001 > From: Luca Bacci <[email protected]> > Date: Sat, 13 Dec 2025 14:22:58 +0100 > Subject: [PATCH 3/3] crt: Ensure that stderr is not fully buffered > > CRT libraries other than the UCRT can open stderr in full-buffering > mode. This happens for example when output goes to a pipe. The C > standard disallow such mode on stderr (C23 7.23.3 pt. 7) [1]: > > > as initially opened, the standard error stream is not fully buffered > > Here we ensure that stderr is unbuffered. Note that we can't use line > buffering since it's the same as full buffering [2]: > > > _IOLBF: For some systems this mode provides line buffering. > However on Win32 the behavior is the same as _IOFBF - Full Buffering. > > References: > > 1. > https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#subsection.7.23.3 > 2. > https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setvbuf?view=msvc-170 > 3. https://sourceforge.net/p/mingw/mailman/message/27121137/ > > Signed-off-by: Luca Bacci <[email protected]> > --- > mingw-w64-crt/crt/crtexe.c | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > > diff --git a/mingw-w64-crt/crt/crtexe.c b/mingw-w64-crt/crt/crtexe.c > index 439d1aea..03a5d083 100644 > --- a/mingw-w64-crt/crt/crtexe.c > +++ b/mingw-w64-crt/crt/crtexe.c > @@ -10,6 +10,7 @@ > #include <signal.h> > #include <math.h> > #include <stdlib.h> > +#include <stdio.h> > #include <tchar.h> > #include <sect_attribs.h> > #include <locale.h> > @@ -215,6 +216,17 @@ __tmainCRTStartup (void) > if (ret != 0) > _amsg_exit (8); /* _RT_SPACEARG */ > > + /* Before the UCRT stderr could be opened in full buffering > + * mode, for example when output goes to a pipe. > + * > + * The C standard disallow full buffering on stderr. Note > + * that line buffering is the same as full buffering in the > + * Windows CRT, so we have to disable buffering altogether. > + */ > + ret = setvbuf (stderr, NULL, _IONBF, 0); > + if (ret != 0) > + return 255; This will break all GUI Windows applications as they are started by OS without the valid stdin, stdout and stderr. Hence setvbuf will fail on stderr. > + > _initterm (__xc_a, __xc_z); /* C++ initialization */ > __main (); > > -- > 2.49.0.windows.1 > _______________________________________________ Mingw-w64-public mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
