diff options
Diffstat (limited to 'compat/snprintf.c')
-rw-r--r-- | compat/snprintf.c | 35 |
1 files changed, 32 insertions, 3 deletions
diff --git a/compat/snprintf.c b/compat/snprintf.c index dbfc2d6b6e..42ea1ac110 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -1,12 +1,37 @@ #include "../git-compat-util.h" +/* + * The size parameter specifies the available space, i.e. includes + * the trailing NUL byte; but Windows's vsnprintf uses the entire + * buffer and avoids the trailing NUL, should the buffer be exactly + * big enough for the result. Defining SNPRINTF_SIZE_CORR to 1 will + * therefore remove 1 byte from the reported buffer size, so we + * always have room for a trailing NUL byte. + */ +#ifndef SNPRINTF_SIZE_CORR +#if defined(WIN32) && (!defined(__GNUC__) || __GNUC__ < 4) +#define SNPRINTF_SIZE_CORR 1 +#else +#define SNPRINTF_SIZE_CORR 0 +#endif +#endif + #undef vsnprintf int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) { + va_list cp; char *s; - int ret; + int ret = -1; - ret = vsnprintf(str, maxsize, format, ap); + if (maxsize > 0) { + 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 */ + str[maxsize-1] = 0; + } if (ret != -1) return ret; @@ -20,7 +45,11 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) if (! str) break; s = str; - ret = vsnprintf(str, maxsize, format, ap); + va_copy(cp, ap); + ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp); + va_end(cp); + if (ret == maxsize-1) + ret = -1; } free(s); return ret; |