summaryrefslogtreecommitdiff
path: root/compat/snprintf.c
diff options
context:
space:
mode:
authorLibravatar Jeff King <peff@peff.net>2011-12-12 09:25:51 -0500
committerLibravatar Junio C Hamano <gitster@pobox.com>2011-12-12 09:09:35 -0800
commita9bfbc5b698103b1553e1023c4f77001cc861e79 (patch)
treec7357e4a4a70b5fc712770da1461717d4c395d06 /compat/snprintf.c
parentcompat: fall back on __va_copy if available (diff)
downloadtgif-a9bfbc5b698103b1553e1023c4f77001cc861e79.tar.xz
compat/snprintf: don't look at va_list twice
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>
Diffstat (limited to 'compat/snprintf.c')
-rw-r--r--compat/snprintf.c9
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;
}