Ken Thomases : libwine: Make [v]snprintW() always null-terminate the buffer , even if it's short.

Alexandre Julliard julliard at winehq.org
Wed Apr 10 14:16:16 CDT 2013


Module: wine
Branch: master
Commit: 71377c5652a2125b46ea7ad8651f73c1852a0083
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=71377c5652a2125b46ea7ad8651f73c1852a0083

Author: Ken Thomases <ken at codeweavers.com>
Date:   Wed Apr 10 08:40:02 2013 -0500

libwine: Make [v]snprintW() always null-terminate the buffer, even if it's short.

---

 libs/wine/string.c |   67 ++++++++++++++++++++++++++++++---------------------
 1 files changed, 39 insertions(+), 28 deletions(-)

diff --git a/libs/wine/string.c b/libs/wine/string.c
index 0b42ea8..f2a9bd3 100644
--- a/libs/wine/string.c
+++ b/libs/wine/string.c
@@ -300,7 +300,7 @@ noconv:
 
 
 /* format a WCHAR string according to a printf format; helper for vsnprintfW */
-static int format_string( WCHAR *buffer, size_t len, const char *format, const WCHAR *str, int str_len )
+static size_t format_string( WCHAR *buffer, size_t len, const char *format, const WCHAR *str, int str_len )
 {
     size_t count = 0;
     int i, left_align = 0, width = 0, max = 0;
@@ -331,18 +331,25 @@ static int format_string( WCHAR *buffer, size_t len, const char *format, const W
 
     if (!left_align && width > max)
     {
-        if ((count += width - max) >= len) return -1;
-        for (i = 0; i < width - max; i++) *buffer++ = ' ';
+        for (i = 0; i < width - max; i++)
+        {
+            if (count++ < len)
+                *buffer++ = ' ';
+        }
     }
 
-    if ((count += max) >= len) return -1;
-    memcpy( buffer, str, max * sizeof(WCHAR) );
+    if (count < len)
+        memcpy( buffer, str, min( max, len - count ) * sizeof(WCHAR) );
+    count += max;
     buffer += max;
 
     if (left_align && width > max)
     {
-        if ((count += width - max) >= len) return -1;
-        for (i = 0; i < width - max; i++) *buffer++ = ' ';
+        for (i = 0; i < width - max; i++)
+        {
+            if (count++ < len)
+                *buffer++ = ' ';
+        }
     }
     return count;
 }
@@ -357,17 +364,16 @@ int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
     {
         while (*iter && *iter != '%')
         {
-            if (written++ >= len)
-                return -1;
-            *str++ = *iter++;
+            if (written++ < len)
+                *str++ = *iter;
+            iter++;
         }
         if (*iter == '%')
         {
             if (iter[1] == '%')
             {
-                if (written++ >= len)
-                    return -1;
-                *str++ = '%'; /* "%%"->'%' */
+                if (written++ < len)
+                    *str++ = '%'; /* "%%"->'%' */
                 iter += 2;
                 continue;
             }
@@ -422,13 +428,13 @@ int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
             {
                 static const WCHAR none[] = { '(','n','u','l','l',')',0 };
                 const WCHAR *wstr = va_arg(valist, const WCHAR *);
-                int count;
+                size_t remaining = written < len ? len - written : 0;
+                size_t count;
 
                 *fmta++ = 's';
                 *fmta = 0;
-                count = format_string( str, len - written, fmtbufa, wstr ? wstr : none, -1 );
-                if (count == -1) return -1;
-                str += count;
+                count = format_string( str, remaining, fmtbufa, wstr ? wstr : none, -1 );
+                str += min( count, remaining );
                 written += count;
                 iter++;
                 break;
@@ -437,14 +443,14 @@ int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
             case 'c':
             {
                 WCHAR wstr;
-                int count;
+                size_t remaining = written < len ? len - written : 0;
+                size_t count;
 
                 wstr = va_arg(valist, int);
                 *fmta++ = 's';
                 *fmta = 0;
-                count = format_string( str, len - written, fmtbufa, &wstr, 1 );
-                if (count == -1) return -1;
-                str += count;
+                count = format_string( str, remaining, fmtbufa, &wstr, 1 );
+                str += min( count, remaining );
                 written += count;
                 iter++;
                 break;
@@ -475,9 +481,9 @@ int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
                 }
                 while (*bufaiter)
                 {
-                    if (written++ >= len)
-                        return -1;
-                    *str++ = *bufaiter++;
+                    if (written++ < len)
+                        *str++ = *bufaiter;
+                    bufaiter++;
                 }
                 iter++;
                 break;
@@ -485,10 +491,15 @@ int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
             }
         }
     }
-    if (written >= len)
-        return -1;
-    *str++ = 0;
-    return (int)written;
+    if (len)
+    {
+        if (written >= len)
+            str--;
+        *str++ = 0;
+    }
+
+    /* FIXME: POSIX [v]snprintf() returns the equivalent of written, not -1, on short buffer. */
+    return written < len ? (int)written : -1;
 }
 
 int vsprintfW( WCHAR *str, const WCHAR *format, va_list valist )




More information about the wine-cvs mailing list