summaryrefslogtreecommitdiff
path: root/compat/snprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'compat/snprintf.c')
-rw-r--r--compat/snprintf.c35
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;