Skip to content

Commit a9bfbc5

Browse files
peffgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 26db0f2 commit a9bfbc5

File tree

1 file changed

+7
-2
lines changed

1 file changed

+7
-2
lines changed

compat/snprintf.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@
1919
#undef vsnprintf
2020
int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
2121
{
22+
va_list cp;
2223
char *s;
2324
int ret = -1;
2425

2526
if (maxsize > 0) {
26-
ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
27+
va_copy(cp, ap);
28+
ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);
29+
va_end(cp);
2730
if (ret == maxsize-1)
2831
ret = -1;
2932
/* 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)
4245
if (! str)
4346
break;
4447
s = str;
45-
ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
48+
va_copy(cp, ap);
49+
ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);
50+
va_end(cp);
4651
if (ret == maxsize-1)
4752
ret = -1;
4853
}

0 commit comments

Comments
 (0)