Code

compat/snprintf: don't look at va_list twice
authorJeff King <peff@peff.net>
Mon, 12 Dec 2011 14:25:51 +0000 (09:25 -0500)
committerJunio C Hamano <gitster@pobox.com>
Mon, 12 Dec 2011 17:09:35 +0000 (09:09 -0800)
If you define SNPRINTF_RETURNS_BOGUS, we use a special
git_vsnprintf wrapper assumes that vsnprintf returns "-1"
instead of the number of characters that you would need to
store the result.

To do this, it invokes vsnprintf multiple times, growing a
heap buffer until we have enough space to hold the result.
However, this means we evaluate the va_list parameter
multiple times, which is generally a bad thing (it may be
modified by calls to vsnprintf, yielding undefined
behavior).

Instead, we must va_copy it and hand the copy to vsnprintf,
so we always have a pristine va_list.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
compat/snprintf.c

index e1e0e7543d9414726122c121b7909bf73809a81a..42ea1ac110813bbd16e77cfbc36f16e6a5e9ddb2 100644 (file)
 #undef vsnprintf
 int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
 {
+       va_list cp;
        char *s;
        int ret = -1;
 
        if (maxsize > 0) {
-               ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
+               va_copy(cp, ap);
+               ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);
+               va_end(cp);
                if (ret == maxsize-1)
                        ret = -1;
                /* Windows does not NUL-terminate if result fills buffer */
@@ -42,7 +45,9 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
                if (! str)
                        break;
                s = str;
-               ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
+               va_copy(cp, ap);
+               ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);
+               va_end(cp);
                if (ret == maxsize-1)
                        ret = -1;
        }