Hello! Based on raymod2 suggestion on IRC, I prepared full patch and tested it that snprintf() and vsnprintf() works correctly.
Patch is attached in email as jon_y on IRC suggested. I fixed directly __ms_snprintf() and __ms_vsnprintf() wrappers (around msvcrt's _snprintf()/_vsnprintf() calls) which are called by snprintf() and vsnprintf() static functions defined in stdio.h header file. In patch I also removed vsnprintf == _vsnprintf and snprintf == _snprintf aliases as they wrong, snprintf() is not same as msvcrt's _snprintf() function, and above __ms_snprintf() or __ms_vsnprintf() wrapper is needed. PS: Please CC me as I'm not subscribed to list. On Sunday 16 February 2020 22:03:21 Pali Rohár wrote: > Hello! Year ago I sent this email about snprintf() problem in mingw-w64 > but I have not received any response yet. > > For one week I tried to contact mingw-w64 developers on IRC #mingw-w64, > but nobody replied, so now I do not know if there are some active people > in mingw-w64 project or not... > > Just resending this email again. > > Btw, if macro is not suitable then it is possible to write normal > snprintf function which would call _snprintf() and _scprintf() as in > that macro. > > On Friday 03 May 2019 10:39:46 Pali Rohár wrote: > > Hello! > > > > snprintf() function in mingw-w64 is broken. Seems that it just calls > > MSVC's _snprintf() function which is not same as snprintf(). MSVC until > > ucrt does not provide snprintf() at all, just _snprintf(). > > > > Differences are that MSVC's _snprintf() does not ensure that filled > > buffer would be null-termed and when overflow occurs it returns -1 > > instead of length which is needed to fully format string. > > > > See following example: > > > > #include <stdio.h> > > > > int main() { > > char buf[5] = "XXXX"; > > int ret = snprintf(buf, 3, "%d", 123456789); > > printf("buf=%s ret=%d\n", buf, ret); > > return 0; > > } > > > > It prints: > > > > buf=123X ret=-1 > > > > So for MSVC's _snprintf() it is needed to write wrapper, e.g. following: > > > > #define snprintf(str, size, format, ...) ( (((size_t)(size) > 0) ? > > (_snprintf((str), (size), (format), __VA_ARGS__), ((char > > *)str)[(size_t)(size)-1] = 0, 0) : 0), _scprintf((format), __VA_ARGS__) ) > > > > It is simple inline-able macro so it does not increase executable code > > size too much. > > > > MSVC's _scprintf() function returns length of formatted string, so > > exactly what snprintf() return value should be. > > > > With that snprintf() define, output of above example is: > > > > buf=12 ret=9 > > > > Which is correct now. > > > > Would you consider fixing snprintf() in mingw-w64? > > > > Similarly also vsnprintf() can be fixed: > > > > #define vsnprintf(str, size, format, ap) ( (((size_t)(size) > 0) ? > > (_vsnprintf((str), (size), (format), (ap)), ((char *)str)[(size_t)(size)-1] > > = 0, 0) : 0), _vscprintf((format), (ap)) ) > > > -- Pali Rohár pali.ro...@gmail.com
diff --git a/mingw-w64-crt/stdio/asprintf.c b/mingw-w64-crt/stdio/asprintf.c index 4e7db60d..c30d6a24 100644 --- a/mingw-w64-crt/stdio/asprintf.c +++ b/mingw-w64-crt/stdio/asprintf.c @@ -12,7 +12,7 @@ int asprintf(char ** __restrict__ ret, int len; va_start(ap,format); /* Get Length */ - len = _vsnprintf(NULL,0,format,ap); + len = _vscprintf(format,ap); if (len < 0) goto _end; /* +1 for \0 terminator. */ *ret = malloc(len + 1); diff --git a/mingw-w64-crt/stdio/snprintf.c b/mingw-w64-crt/stdio/snprintf.c index 93300113..0bb5556f 100644 --- a/mingw-w64-crt/stdio/snprintf.c +++ b/mingw-w64-crt/stdio/snprintf.c @@ -12,7 +12,27 @@ int __cdecl __ms_snprintf(char* buffer, size_t n, const char *format, ...) va_list argptr; va_start(argptr, format); + + /* _vsnprintf() does not work with zero length buffer + * so count number of character by _vscprintf() call */ + if (n == 0 || !buffer) + { + retval = _vscprintf(format, argptr); + va_end(argptr); + return retval; + } + retval = _vsnprintf (buffer, n, format, argptr); + + /* _vsnprintf() returns negative number if buffer is too small + * so count number of character by _vscprintf() call */ + if (retval < 0) + retval = _vscprintf(format, argptr); + + /* _vsnprintf() does not fill trailing null byte if there is not place for it */ + if ((size_t)retval >= n) + buffer[n-1] = '\0'; + va_end(argptr); return retval; } diff --git a/mingw-w64-crt/stdio/vasprintf.c b/mingw-w64-crt/stdio/vasprintf.c index 7036e96c..b441fa18 100644 --- a/mingw-w64-crt/stdio/vasprintf.c +++ b/mingw-w64-crt/stdio/vasprintf.c @@ -10,7 +10,7 @@ int vasprintf(char ** __restrict__ ret, va_list ap) { int len; /* Get Length */ - len = _vsnprintf(NULL,0,format,ap); + len = _vscprintf(format,ap); if (len < 0) return -1; /* +1 for \0 terminator. */ *ret = malloc(len + 1); diff --git a/mingw-w64-crt/stdio/vsnprintf.c b/mingw-w64-crt/stdio/vsnprintf.c index 1346c5c8..36418670 100644 --- a/mingw-w64-crt/stdio/vsnprintf.c +++ b/mingw-w64-crt/stdio/vsnprintf.c @@ -9,5 +9,23 @@ int __cdecl __ms_vsnprintf (char *s,size_t n,const char *format,va_list arg) { - return _vsnprintf(s, n, format, arg); + int retval; + + /* _vsnprintf() does not work with zero length buffer + * so count number of character by _vscprintf() call */ + if (n == 0 || !s) + return _vscprintf(format, arg); + + retval = _vsnprintf(s, n, format, arg); + + /* _vsnprintf() returns negative number if buffer is too small + * so count number of character by _vscprintf() call */ + if (retval < 0) + retval = _vscprintf(format, arg); + + /* _vsnprintf() does not fill trailing null byte if there is not place for it */ + if ((size_t)retval >= n) + s[n-1] = '\0'; + + return retval; } diff --git a/mingw-w64-crt/lib-common/msvcr120_app.def.in b/mingw-w64-crt/lib-common/msvcr120_app.def.in index 38ac14a8..9ae4e450 100644 --- a/mingw-w64-crt/lib-common/msvcr120_app.def.in +++ b/mingw-w64-crt/lib-common/msvcr120_app.def.in @@ -1802,8 +1802,6 @@ _vscwprintf_l F_X86_ANY(_vscwprintf_p) _vscwprintf_p_l _vsnprintf -vsnprintf == _vsnprintf -snprintf == _snprintf _vsnprintf_c _vsnprintf_c_l _vsnprintf_l diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in index 702f2aee..f91d04df 100644 --- a/mingw-w64-crt/lib-common/msvcrt.def.in +++ b/mingw-w64-crt/lib-common/msvcrt.def.in @@ -1546,8 +1546,6 @@ vfwprintf vfwprintf_s vprintf vprintf_s -vsnprintf == _vsnprintf -snprintf == _snprintf vsprintf ; vsprintf_s replaced by emu vswprintf diff --git a/mingw-w64-crt/lib32/msvcr100.def.in b/mingw-w64-crt/lib32/msvcr100.def.in index 57fbdf66..ad1f832e 100644 --- a/mingw-w64-crt/lib32/msvcr100.def.in +++ b/mingw-w64-crt/lib32/msvcr100.def.in @@ -1490,7 +1490,6 @@ _vscwprintf_l _vscwprintf_p _vscwprintf_p_l _vsnprintf -vsnprintf == _vsnprintf _vsnprintf_c _vsnprintf_c_l _vsnprintf_l diff --git a/mingw-w64-crt/lib32/msvcr110.def.in b/mingw-w64-crt/lib32/msvcr110.def.in index b416f213..2a56c514 100644 --- a/mingw-w64-crt/lib32/msvcr110.def.in +++ b/mingw-w64-crt/lib32/msvcr110.def.in @@ -1623,7 +1623,6 @@ _vscwprintf_l _vscwprintf_p _vscwprintf_p_l _vsnprintf -vsnprintf == _vsnprintf _vsnprintf_c _vsnprintf_c_l _vsnprintf_l diff --git a/mingw-w64-crt/lib32/msvcr120.def.in b/mingw-w64-crt/lib32/msvcr120.def.in index bbe20b64..6b92a0b6 100644 --- a/mingw-w64-crt/lib32/msvcr120.def.in +++ b/mingw-w64-crt/lib32/msvcr120.def.in @@ -2245,8 +2245,6 @@ vfwscanf vfwscanf_s vprintf vprintf_s -vsnprintf == _vsnprintf -snprintf == _snprintf snwprintf == _snwprintf vsnwprintf == _vsnwprintf vscanf diff --git a/mingw-w64-crt/lib32/msvcr120d.def.in b/mingw-w64-crt/lib32/msvcr120d.def.in index b8877256..afa07b22 100644 --- a/mingw-w64-crt/lib32/msvcr120d.def.in +++ b/mingw-w64-crt/lib32/msvcr120d.def.in @@ -2313,8 +2313,6 @@ vfwscanf vfwscanf_s vprintf vprintf_s -vsnprintf == _vsnprintf -snprintf == _snprintf snwprintf == _snwprintf vsnwprintf == _vsnwprintf vscanf diff --git a/mingw-w64-crt/lib32/msvcr80.def.in b/mingw-w64-crt/lib32/msvcr80.def.in index 507ea5bb..c1328aad 100644 --- a/mingw-w64-crt/lib32/msvcr80.def.in +++ b/mingw-w64-crt/lib32/msvcr80.def.in @@ -445,7 +445,6 @@ _unloaddll _unlock _utime _vsnprintf -vsnprintf == _vsnprintf _vsnwprintf _waccess _wasctime diff --git a/mingw-w64-crt/lib32/msvcr90.def.in b/mingw-w64-crt/lib32/msvcr90.def.in index bb1aa9f7..8d09a70c 100644 --- a/mingw-w64-crt/lib32/msvcr90.def.in +++ b/mingw-w64-crt/lib32/msvcr90.def.in @@ -1124,7 +1124,6 @@ _vscwprintf_l _vscwprintf_p _vscwprintf_p_l _vsnprintf -vsnprintf == _vsnprintf _vsnprintf_c _vsnprintf_c_l _vsnprintf_l diff --git a/mingw-w64-crt/lib32/msvcr90d.def.in b/mingw-w64-crt/lib32/msvcr90d.def.in index fab4cd73..65816ec0 100644 --- a/mingw-w64-crt/lib32/msvcr90d.def.in +++ b/mingw-w64-crt/lib32/msvcr90d.def.in @@ -1190,7 +1190,6 @@ _vscwprintf_l _vscwprintf_p _vscwprintf_p_l _vsnprintf -vsnprintf == _vsnprintf _vsnprintf_c _vsnprintf_c_l _vsnprintf_l diff --git a/mingw-w64-crt/lib64/msvcr100.def.in b/mingw-w64-crt/lib64/msvcr100.def.in index a2c10e5b..aaeff0dd 100644 --- a/mingw-w64-crt/lib64/msvcr100.def.in +++ b/mingw-w64-crt/lib64/msvcr100.def.in @@ -1437,7 +1437,6 @@ _vscwprintf_l _vscwprintf_p _vscwprintf_p_l _vsnprintf -vsnprintf == _vsnprintf _vsnprintf_c _vsnprintf_c_l _vsnprintf_l diff --git a/mingw-w64-crt/lib64/msvcr110.def.in b/mingw-w64-crt/lib64/msvcr110.def.in index be34f3a5..081b6a2f 100644 --- a/mingw-w64-crt/lib64/msvcr110.def.in +++ b/mingw-w64-crt/lib64/msvcr110.def.in @@ -1561,7 +1561,6 @@ _vscwprintf_l _vscwprintf_p _vscwprintf_p_l _vsnprintf -vsnprintf == _vsnprintf _vsnprintf_c _vsnprintf_c_l _vsnprintf_l diff --git a/mingw-w64-crt/lib64/msvcr120.def.in b/mingw-w64-crt/lib64/msvcr120.def.in index 502d2904..97e4f5e3 100644 --- a/mingw-w64-crt/lib64/msvcr120.def.in +++ b/mingw-w64-crt/lib64/msvcr120.def.in @@ -1601,8 +1601,6 @@ _vsnprintf_c_l _vsnprintf_l _vsnprintf_s _vsnprintf_s_l -vsnprintf == _vsnprintf -snprintf == _snprintf snwprintf == _snwprintf vsnwprintf == _vsnwprintf _vsnwprintf diff --git a/mingw-w64-crt/lib64/msvcr120d.def.in b/mingw-w64-crt/lib64/msvcr120d.def.in index 65838206..56bda541 100644 --- a/mingw-w64-crt/lib64/msvcr120d.def.in +++ b/mingw-w64-crt/lib64/msvcr120d.def.in @@ -1659,8 +1659,6 @@ _vsnprintf_c_l _vsnprintf_l _vsnprintf_s _vsnprintf_s_l -vsnprintf == _vsnprintf -snprintf == _snprintf snwprintf == _snwprintf vsnwprintf == _vsnwprintf _vsnwprintf diff --git a/mingw-w64-crt/lib64/msvcr80.def.in b/mingw-w64-crt/lib64/msvcr80.def.in index cf263a53..c1ef3f03 100644 --- a/mingw-w64-crt/lib64/msvcr80.def.in +++ b/mingw-w64-crt/lib64/msvcr80.def.in @@ -555,7 +555,6 @@ _utime64 _vscprintf _vscwprintf _vsnprintf -vsnprintf == _vsnprintf _vsnwprintf _waccess _wasctime diff --git a/mingw-w64-crt/lib64/msvcr90.def.in b/mingw-w64-crt/lib64/msvcr90.def.in index 9953c8d6..4fcaedcb 100644 --- a/mingw-w64-crt/lib64/msvcr90.def.in +++ b/mingw-w64-crt/lib64/msvcr90.def.in @@ -1057,7 +1057,6 @@ _vscwprintf_l _vscwprintf_p _vscwprintf_p_l _vsnprintf -vsnprintf == _vsnprintf _vsnprintf_c _vsnprintf_c_l _vsnprintf_l diff --git a/mingw-w64-crt/lib64/msvcr90d.def.in b/mingw-w64-crt/lib64/msvcr90d.def.in index 3d339f3a..0b174600 100644 --- a/mingw-w64-crt/lib64/msvcr90d.def.in +++ b/mingw-w64-crt/lib64/msvcr90d.def.in @@ -1117,7 +1117,6 @@ _vscwprintf_l _vscwprintf_p _vscwprintf_p_l _vsnprintf -vsnprintf == _vsnprintf _vsnprintf_c _vsnprintf_c_l _vsnprintf_l diff --git a/mingw-w64-tools/genstubdll/sample/ms.def b/mingw-w64-tools/genstubdll/sample/ms.def index b862f992..1cb08ef3 100644 --- a/mingw-w64-tools/genstubdll/sample/ms.def +++ b/mingw-w64-tools/genstubdll/sample/ms.def @@ -1371,8 +1371,6 @@ vfwprintf vfwprintf_s vprintf vprintf_s -vsnprintf == _vsnprintf -snprintf == _snprintf vsprintf ; vsprintf_s replaced by emu vswprintf
signature.asc
Description: PGP signature
_______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public