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

Attachment: 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

Reply via email to