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

Reply via email to