On Tuesday 12 November 2024 23:13:28 Martin Storsjö wrote: > On Tue, 12 Nov 2024, Pali Rohár wrote: > > > > See https://github.com/mstorsjo/llvm-mingw/commits/c95-test for the added > > > tests. At the end, I have two "WIP: test: Waive ..." commits that makes > > > the > > > tests pass, covering up the issues that I found. > > > > > > These tests are in the form of one large file, test/crt-test.c, which can > > > be > > > compiled with MSVC (and with unix compilers as well, to crosscheck CRT > > > behaviours there). > > > > I have just two comments. Otherwise everything looks good. > > > > You wrote this code: > > > > #ifndef __GLIBC__ > > // On overflow, glibc doesn't seem to null terminate the array. > > TEST_INT(wbuf2[ARRAYLEN(wbuf2)-1], '\0'); > > #endif > > > > This is known glibc issue and was fixed just year ago in version 2.37: > > https://sourceware.org/bugzilla/show_bug.cgi?id=27857 > > > > You could extend that check with __GLIBC__ and __GLIBC_MINOR__ > > preprocessor macros to run that test on 2.37+ glibc versions too. > > Oh, thanks for the reference! Yeah this felt like a big omission. > > I'll see if I add such a check, or if I just keep it simple. > > > And I spotted that for vsnwprintf test you have comment: > > // On overflow, snwprintf null terminates. > > > > There is missing leading "v" in comment for function name. > > Thanks, will fix. > > > > The issues I ran into were the following: > > > > > > - In C++ mode, we have an inline overload of wcstok() with 2 parameters. > > > However, this doesn't work when compiling in -O0 mode; in this mode, the > > > compiler predefines __NO_INLINE__, which makes our headers set > > > __CRT__NO_INLINE and skip inline functions. This maybe is reasonable for > > > performance/code size cases, but here, it affects what code is valid and > > > can > > > be built or not. So I wonder if we should skip the check for > > > __CRT__NO_INLINE for the 2 parameter C++ overload of wcstok? > > > > I think it makes sense. The code is C++-only with extern "C++" so we > > should drop "!defined(__CRT__NO_INLINE)" check and maybe also changing > > __CRT_INLINE directly to "inline". So it always use C++ inline semantics > > to prevent linking problems. > > Thanks, this sounds reasonable to me.
Ok, I will include it into next batch. > > > - The commit message explanation of _swprintf_c seems weird. The commit > > > message says: > > > > > > _(v)swprintf_c - clears the first wide character in buffer on error > > > (error means that there is no space for nul-term or > > > conversion error occurred) > > > > > > However I don't see that behaviour (clearing the _first_ char in the > > > buffer > > > on error sounds odd - then the whole buffer would be an empty string?). > > > Can > > > you recheck this explanation? In any case, this function seemed fringe > > > enough that I didn't add a test for it. > > > > Ok. I will recheck it. IIRC I tried to decode header files, and I'm not > > sure if I still have test case for this function, as this function > > something not very widely used. > > Indeed, it seems very rare. Yes, it is rare and I have included it into commit message just because of completeness and to explain why cannot use it as alias for the compliant swprintf. > > Anyway this comment should apply for msvcr80-msvcr120. Not for msvcrt > > and neither for ucrt. > > Ah, that would probably explain it. I think I tested the behaviour of it > with MSVC with UCRT possibly, or just the mingw behaviour with msvcrt/ucrt. > > In any case, the function is such a rare one that I chose to skip testing of > it. I wrote results in previous email. UCRT has really different behavior than msvcr*. > > > - The functions snwprintf and vswnprintf can't be found, when linking > > > against msvcrt, with -D__USE_MINGW_ANSI_STDIO=0. There's a patch "crt: Fix > > > non-ISO (v)snwprintf() functions when __USE_MINGW_ANSI_STDIO=0" in this > > > patchset, but despite this, I seem to be running into this issue. > > > > I see. I forgot to add __MINGW_ASM_CALL into header file for this case. > > And also I forgot to include aliases for import symbols (in case > > somebody does not use header file with __MINGW_ASM_CALL). So missing of > > both these two parts caused linking error. > > > > In attachment I'm sending fixup for this issue. > > Thanks, this does seem to work fine for these tests! > > > > - I noted that MSVC (v)swprintf returns the required buffer length, if > > > called with a NULL buffer and 0 buffer size, so I added a test for it. > > > But I > > > didn't get this behaviour on either Glibc, Musl or Darwin, so I guess it's > > > not necessary to test this case and care about it? > > > > IMHO, this MSVC behavior is a bug and not compliant with C95+ > > specifications. > > > > N1570 ISO/IEC 9899:201x (C11) specification for swprintf in 7.29.2.3 says: > > > > "The swprintf function returns the number of wide characters written in > > the array, not counting the terminating null wide character, or a > > negative value if an encoding error occurred or if n or more wide > > characters were requested to be written." > > > > My understanding is that when swprintf is called with N=0 then more wide > > characters are requested to be written (because at least nul-term wide > > has to be written) and so negative value has to be returned. > > Ah, right. > > > Maybe we should rather test that swprintf returns negative value in this > > case and skip this test case for MSVC? > > I think I'll just skip this test altogether, as we get the wrong result with > UCRT in mingw as well, and with msvcrt when not using > __USE_MINGW_ANSI_STDIO. That is bad if we are getting wrong/different results. I looked at it and it is a real bug which you found. It is in the file: mingw-w64-crt/stdio/vswprintf.c int __cdecl __ms_vswprintf(wchar_t *__restrict__ ws, size_t n, const wchar_t *__restrict__ format, va_list arg) { int retval; retval = _vsnwprintf(ws, n-1, format, arg); When n=0 then _vsnwprintf is called with MAX_SIZE_T value. Now I checked that _vsnwprintf() in msvcr* returns -1 when n=0. I'm going to apply following change to fix n-1 underflow: diff --git a/mingw-w64-crt/stdio/vswprintf.c b/mingw-w64-crt/stdio/vswprintf.c index f7bdc3cdc897..7edc52050711 100644 --- a/mingw-w64-crt/stdio/vswprintf.c +++ b/mingw-w64-crt/stdio/vswprintf.c @@ -11,6 +11,9 @@ int __cdecl __ms_vswprintf(wchar_t *__restrict__ ws, size_t n, const wchar_t *__ { int retval; + if (n == 0) + return -1; + retval = _vsnwprintf(ws, n-1, format, arg); /* _vsnwprintf() does not fill trailing nul wide char if there is not place for it */ It is fine? I think that the test for this n=0 case is really useful as it already found a bug in my new code. > With all these fixes in place, I think this patchset starts to look good. > Can you post a rebased version (there's a bit of conflicts with the recent > refactoring in Makefile.am) and with all the assorted fixes squashed in the > right places? I can then run it through all my tests and see if we can hope > to land this soon. > > > // Martin Yes, I will send a new rebased version with all fixups applied. _______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public