Add compat/snprintf.c for systems that return bogus
Some systems (namely HPUX and Windows) return -1 when maxsize in snprintf() and in vsnprintf() is reached. So replace snprintf() and vsnprintf() functions with our own ones that return correct value upon overflow. [jc: verified that review comments by J6t have been incorporated, and tightened the check to verify the resulting buffer contents, suggested by Wayne Davison] Signed-off-by: Michal Rokos <michal.rokos@nextsoft.cz> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Michal Rokos committed
Mar 5, 2008 at 16:46 UTC
c4582f93a263bea534288e7f7ad8937405964cd4
5 files changed
+92
Makefile
+8
@@ -3,6 +3,10 @@ all::
3
4
# Define V=1 to have a more verbose compile.
5
#
6
+# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
7
+# or vsnprintf() return -1 instead of number of characters which would
8
+# have been written to the final string if enough space had been available.
9
+#
10
# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds
11
# when attempting to read from an fopen'ed directory.
12
#
@@ -629,6 +633,10 @@ endif
633
ifdef NO_C99_FORMAT
634
BASIC_CFLAGS += -DNO_C99_FORMAT
635
endif
636
+ifdef SNPRINTF_RETURNS_BOGUS
637
+ COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
638
+ COMPAT_OBJS += compat/snprintf.o
639
+endif
640
ifdef FREAD_READS_DIRECTORIES
641
COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
642
COMPAT_OBJS += compat/fopen.o
compat/snprintf.c
new
+40
@@ -0,0 +1,40 @@
1
+#include "../git-compat-util.h"
2
+
3
+#undef vsnprintf
4
+int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
5
+{
6
+ char *s;
7
+ int ret;
8
+
9
+ ret = vsnprintf(str, maxsize, format, ap);
10
+ if (ret != -1)
11
+ return ret;
12
+
13
+ s = NULL;
14
+ if (maxsize < 128)
15
+ maxsize = 128;
16
+
17
+ while (ret == -1) {
18
+ maxsize *= 4;
19
+ str = realloc(s, maxsize);
20
+ if (! str)
21
+ break;
22
+ s = str;
23
+ ret = vsnprintf(str, maxsize, format, ap);
24
+ }
25
+ free(s);
26
+ return ret;
27
+}
28
+
29
+int git_snprintf(char *str, size_t maxsize, const char *format, ...)
30
+{
31
+ va_list ap;
32
+ int ret;
33
+
34
+ va_start(ap, format);
35
+ ret = git_vsnprintf(str, maxsize, format, ap);
36
+ va_end(ap);
37
+
38
+ return ret;
39
+}
40
+
config.mak.in
+1
@@ -46,3 +46,4 @@ NO_MKDTEMP=@NO_MKDTEMP@
46
NO_ICONV=@NO_ICONV@
47
OLD_ICONV=@OLD_ICONV@
48
NO_DEFLATE_BOUND=@NO_DEFLATE_BOUND@
49
+SNPRINTF_RETURNS_BOGUS=@SNPRINTF_RETURNS_BOGUS@
configure.ac
+34
@@ -326,6 +326,40 @@ else
326
NO_C99_FORMAT=
327
fi
328
AC_SUBST(NO_C99_FORMAT)
329
+#
330
+# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
331
+# or vsnprintf() return -1 instead of number of characters which would
332
+# have been written to the final string if enough space had been available.
333
+AC_CACHE_CHECK([whether snprintf() and/or vsnprintf() return bogus value],
334
+ [ac_cv_snprintf_returns_bogus],
335
+[
336
+AC_RUN_IFELSE(
337
+ [AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
338
+ #include "stdarg.h"
339
+
340
+ int test_vsnprintf(char *str, size_t maxsize, const char *format, ...)
341
+ {
342
+ int ret;
343
+ va_list ap;
344
+ va_start(ap, format);
345
+ ret = vsnprintf(str, maxsize, format, ap);
346
+ va_end(ap);
347
+ return ret;
348
+ }],
349
+ [[char buf[6];
350
+ if (test_vsnprintf(buf, 3, "%s", "12345") != 5
351
+ || strcmp(buf, "12")) return 1;
352
+ if (snprintf(buf, 3, "%s", "12345") != 5
353
+ || strcmp(buf, "12")) return 1]])],
354
+ [ac_cv_snprintf_returns_bogus=no],
355
+ [ac_cv_snprintf_returns_bogus=yes])
356
+])
357
+if test $ac_cv_snprintf_returns_bogus = yes; then
358
+ SNPRINTF_RETURNS_BOGUS=UnfortunatelyYes
359
+else
360
+ SNPRINTF_RETURNS_BOGUS=
361
+fi
362
+AC_SUBST(SNPRINTF_RETURNS_BOGUS)
363
364
365
## Checks for library functions.
git-compat-util.h
+9
@@ -209,6 +209,15 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
209
extern FILE *git_fopen(const char*, const char*);
210
#endif
211
212
+#ifdef SNPRINTF_RETURNS_BOGUS
213
+#define snprintf git_snprintf
214
+extern int git_snprintf(char *str, size_t maxsize,
215
+ const char *format, ...);
216
+#define vsnprintf git_vsnprintf
217
+extern int git_vsnprintf(char *str, size_t maxsize,
218
+ const char *format, va_list ap);
219
+#endif
220
+
221
#ifdef __GLIBC_PREREQ
222
#if __GLIBC_PREREQ(2, 1)
223
#define HAVE_STRCHRNUL