On Wednesday 01 October 2025 17:55:02 LIU Hao wrote:
> 在 2025-6-25 06:29, Pali Rohár 写道:
> > __pformat_wputchars() for snprintf, __pformat_puchats() for swprintf and
> > __pformat_puchats() for snprintf prints all characters including nul chars.
> > So change __pformat_wputchars() for swprintf to align this behavior.
> >
> > This change is needed for swprintf(%wZ) support in follow up change.
> > ---
> > mingw-w64-crt/stdio/mingw_pformat.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/mingw-w64-crt/stdio/mingw_pformat.c
> > b/mingw-w64-crt/stdio/mingw_pformat.c
> > index 9c22aff144fd..a2ef12da2de8 100644
> > --- a/mingw-w64-crt/stdio/mingw_pformat.c
> > +++ b/mingw-w64-crt/stdio/mingw_pformat.c
> > @@ -657,7 +657,7 @@ void __pformat_wputchars( const wchar_t *s, int count,
> > __pformat_t *stream )
> > __pformat_putc( '\x20', stream );
> > len = count;
> > - while(len-- > 0 && *s != 0)
> > + while(len-- > 0)
> > {
> > __pformat_putc(*s++, stream);
> > }
>
> I think this change makes `__pformat_wputchars` not stop when a null
> character is encountered.
Yes.
> However this code is part of an `#if` block, and
> when we have a look at the other branch, it says:
>
> while( (count-- > 0) && ((len = wcrtomb( buf, *s++, &state )) > 0) )
>
> ... which also stops upon a null character when `wcrtomb()` returns zero. Is
> this inconsistency intended?
No, this does not stop upon a null wide character. wcrtomb for wide
null character input L'\0' returns 1 and fill buf[0] with '\0'.
So the len is set to 1 for wide nul character and while loop continues
processing data after wide nul character.
>
> There's also a similar issue in `__pformat_putchars()`:
>
> l = mbrtowc (p, s, strlen (s), &ps);
> if (!l)
> break;
>
> One is not supposed to pass a length of zero (third argument) to
> `mbrtowc()`; no input can be consumed and no output is produced, and our new
> implementation returns `(size_t) -2` in this case, instead of zero.
Ok. This block (when the __BUILD_WIDEAPI is defined) probably looks like
an issue which would be needed to address.
Anyway, if you look at the __pformat_putchars into the '#ifndef __BUILD_WIDEAPI'
block then this one already does not stop on the nul character and
continue execution. There is:
/* Emit the data...
*/
while( count-- )
/*
* copying the requisite number of characters from the input.
*/
__pformat_putc( *s++, stream );
There is no check whether *s is '\0' or not.
>
> I have also made some experiments with my Visual Studio 2022 installation,
> linking against UCRT. It turns out that mostly null characters are not
> terminators, except in the last case:
>
> static WCHAR wstr[] = L"ab\0cd";
> UNICODE_STRING ws1 = {
> .Length = sizeof(wstr) - sizeof(wstr[0]),
> .MaximumLength = sizeof(wstr),
> .Buffer = wstr };
>
> fprintf(stdout, "\n[%lZ]", &ws1); // [ab cd]
> fprintf(stdout, "\n[%7lZ]", &ws1); // [ ab cd]
> fprintf(stdout, "\n[%-7lZ]", &ws1); // [ab cd ]
>
> fwprintf(stderr, L"\n[%lZ]", &ws1); // [ab cd]
> fwprintf(stderr, L"\n[%7lZ]", &ws1); // [ ab cd]
> fwprintf(stderr, L"\n[%-7lZ]", &ws1); // [ab cd ]
>
> static CHAR astr[] = "ab\0cd";
> ANSI_STRING as1 = {
> .Length = sizeof(astr) - sizeof(astr[0]),
> .MaximumLength = sizeof(astr),
> .Buffer = astr };
>
> fprintf(stdout, "\n[%hZ]", &as1); // [ab cd]
> fprintf(stdout, "\n[%7hZ]", &as1); // [ ab cd]
> fprintf(stdout, "\n[%-7hZ]", &as1); // [ab cd ]
>
> fwprintf(stderr, L"\n[%hZ]", &as1); // [ab
> fwprintf(stderr, L"\n[%7hZ]", &as1); // [ ab
> fwprintf(stderr, L"\n[%-7hZ]", &as1); // [ab
>
>
>
> --
> Best regards,
> LIU Hao
Yes, it is messy. I did different tests with different CRT dll libraries
and put comments into code and also in tests to verify this behavior.
Everything which I "measured" is in this patch series.
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public