diff options
author | Jeff King <peff@peff.net> | 2011-12-12 09:25:51 -0500 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2011-12-12 09:09:35 -0800 |
commit | a9bfbc5b698103b1553e1023c4f77001cc861e79 (patch) | |
tree | c7357e4a4a70b5fc712770da1461717d4c395d06 | |
parent | 26db0f2e3afc043e184a5e0ce5eb7c53aeb1f644 (diff) | |
download | git-a9bfbc5b698103b1553e1023c4f77001cc861e79.tar.gz |
compat/snprintf: don't look at va_list twicejk/maint-snprintf-va-copy
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>
-rw-r--r-- | compat/snprintf.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/compat/snprintf.c b/compat/snprintf.c index e1e0e7543d..42ea1ac110 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -19,11 +19,14 @@ #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; } |