? nohup.out ? gmon.out ? time.out ? size.out ? size2.out ? vsnprintf_autostuff.diff Index: acinclude.m4 =================================================================== RCS file: /home/freeciv/CVS/freeciv/acinclude.m4,v retrieving revision 1.7 diff -u -r1.7 acinclude.m4 --- acinclude.m4 2000/08/11 02:31:02 1.7 +++ acinclude.m4 2001/05/19 22:49:33 @@ -482,3 +482,67 @@ [$2]]) LIBS="$templibs" ]) + +dnl @synopsis AC_FUNC_VSNPRINTF +dnl +dnl Check whether there is a reasonably sane vsnprintf() function installed. +dnl "Reasonably sane" in this context means never clobbering memory beyond +dnl the buffer supplied, and having a sensible return value. It is +dnl explicitly allowed not to NUL-terminate the return value, however. +dnl +dnl @version $Id$ +dnl @author Gaute Strokkenes +dnl +AC_DEFUN([AC_FUNC_VSNPRINTF], +[AC_CACHE_CHECK(for working vsnprintf, + ac_cv_func_vsnprintf, +[AC_TRY_RUN( +[#include +#include + +int +doit(char * s, ...) +{ + char buffer[32]; + va_list args; + int r; + + buffer[5] = 'X'; + + va_start(args, s); + r = vsnprintf(buffer, 5, s, args); + va_end(args); + + /* -1 is pre-C99, 7 is C99. */ + + if (r != -1 && r != 7) + exit(1); + + /* We deliberately do not care if the result is NUL-terminated or + not, since this is easy to work around like this. */ + + buffer[4] = 0; + + /* Simple sanity check. */ + + if (strcmp(buffer, "1234")) + exit(1); + + if (buffer[5] != 'X') + exit(1); + + exit(0); +} + +int +main(void) +{ + doit("1234567"); + exit(1); +}], ac_cv_func_vsnprintf=yes, ac_cv_func_vsnprintf=no)]) +if test $ac_cv_func_vsnprintf = yes; then + AC_DEFINE(HAVE_WORKING_VSNPRINTF, 1, + [Define if you have a version of the `vsnprintf' function + that honours the size argument and has a proper return value.]) +fi +])# AC_FUNC_VSNPRINTF Index: aclocal.m4 =================================================================== RCS file: /home/freeciv/CVS/freeciv/aclocal.m4,v retrieving revision 1.13 diff -u -r1.13 aclocal.m4 --- aclocal.m4 2000/08/11 02:31:02 1.13 +++ aclocal.m4 2001/05/19 22:49:33 @@ -1523,4 +1523,3 @@ AC_SUBST(GDK_IMLIB_LIBS) rm -f conf.gdkimlibtest ]) - Index: configure.in =================================================================== RCS file: /home/freeciv/CVS/freeciv/configure.in,v retrieving revision 1.144 diff -u -r1.144 configure.in --- configure.in 2001/04/14 10:26:57 1.144 +++ configure.in 2001/05/19 22:49:33 @@ -456,10 +456,14 @@ AC_TYPE_SIGNAL AC_FUNC_STRCOLL AC_FUNC_VPRINTF +AC_FUNC_VSNPRINTF AC_CHECK_FUNCS(fileno gethostname getpwuid gettimeofday inet_aton \ select snooze strerror strcasecmp strncasecmp \ strlcat strlcpy strstr usleep vsnprintf) + +dnl The use of both AC_FUNC_VSNPRINTF and AC_CHECK_FUNCS(vsnprintf) is +dnl deliberate. dnl Windows fdopen does not work with sockets. if test "x$MINGW32" != "xyes"; then Index: common/ioz.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/ioz.c,v retrieving revision 1.4 diff -u -r1.4 ioz.c --- common/ioz.c 2000/12/02 18:39:34 1.4 +++ common/ioz.c 2001/05/19 22:49:33 @@ -212,9 +212,9 @@ char buffer[4096]; int num; num = my_vsnprintf(buffer, sizeof(buffer), format, ap); - if (num >= sizeof(buffer)) { - freelog(LOG_ERROR, "Too much data: truncated in fz_fprintf (%d/%d)", - num, (int)sizeof(buffer)); + if (num == -1) { + freelog(LOG_ERROR, "Too much data: truncated in fz_fprintf (%lu)", + (unsigned long) sizeof(buffer)); } retval = gzwrite(fp->u.zlib, buffer, (unsigned int)strlen(buffer)); } Index: common/support.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/support.c,v retrieving revision 1.12 diff -u -r1.12 support.c --- common/support.c 2001/02/18 16:28:30 1.12 +++ common/support.c 2001/05/19 22:49:34 @@ -252,64 +252,6 @@ } -#ifdef HAVE_VSNPRINTF -/********************************************************************** - Convenience function used by check_native_vsnprintf() below. - (Can test check_native_vsnprintf() by replacing vsnprintf call - below with vsprintf(), or by changing return value to eg -1.) -***********************************************************************/ -static int test_snprintf(char *str, size_t n, const char *format, ...) -{ - int ret; - va_list ap; - - va_start(ap, format); - ret = vsnprintf(str, n, format, ap); - va_end(ap); - return ret; -} - -/********************************************************************** - This function checks, at runtime, whether a native vsnprintf() meets - our requirements; specifically: - - Should actually obey the parameter n, rather than, eg, just - calling sprintf and ignoring n. - - On truncation, should return the number of chars (not counting - trailing null) which would have been printed, rather than, eg, -1. - Returns 1 if both ok. - Also checks whether null-terminates on truncation, but we don't - base return value on this since it is easy to force this behaviour. - Reports to stderr if DEBUG set (cannot use freelog since that - calls my_vsnprintf). - Could do these checks at configure time, but seems to me easier to - do at runtime on first call... -***********************************************************************/ -static int check_native_vsnprintf(void) -{ - char buf[20] = "abcdefghijkl"; /* 12 + null */ - char *test_str = "0123456789"; - const int ntrunc = 5; - const char one_past = buf[ntrunc]; - int test_len = strlen(test_str); - int ret; - - ret = test_snprintf(buf, ntrunc, "%s", test_str); -#ifdef DEBUG - if (buf[ntrunc] != one_past) { - fprintf(stderr, "debug: test_snprintf wrote past n\n"); - } else if (buf[ntrunc-1] != '\0') { - fprintf(stderr, "debug: test_snprintf did not null-terminate\n"); - } - if (ret != test_len) { - fprintf(stderr, "debug: test_snprintf returned %d," - " not untruncated length %d\n", ret, test_len); - } -#endif - - return (buf[ntrunc]==one_past && ret==test_len); -} -#endif - /********************************************************************** vsnprintf() replacement using a big malloc()ed internal buffer, originally by David Pfitzner @@ -360,84 +302,69 @@ ***********************************************************************/ -/* buffer size: "64k should be big enough for anyone" ;-) */ +/* "64k should be big enough for anyone" ;-) */ #define VSNP_BUF_SIZE (64*1024) int my_vsnprintf(char *str, size_t n, const char *format, va_list ap) { - /* This may be overzealous, but I suspect any triggering of these - * to be bugs. (Do this even if call native function.) - */ + int r; + + /* This may be overzealous, but I suspect any triggering of these to + * be bugs. */ + assert(str); assert(n>0); assert(format); -#ifdef HAVE_VSNPRINTF +#ifdef HAVE_WORKING_VSNPRINTF + r = vsnprintf(str, n, format, ap); + str[n - 1] = 0; + + /* Convert C99 return value to C89. */ + if (r >= n) + return -1; + + return r; +#else { - static int native_is_ok = -1; /* set to 0 or 1 on first call */ + /* Don't use fc_malloc() or freelog() here, since they may call + my_vsnprintf() if it fails. */ - if (native_is_ok == -1) { - native_is_ok = check_native_vsnprintf(); - } + static char *buf; + size_t len; - if (native_is_ok) { - int ret = vsnprintf(str, n, format, ap); - /* Guarantee null-terminated: (native_is_ok means can use ret like this) */ - if (ret >= n) { - str[n-1] = '\0'; - } - return ret; - } - } -#endif - /* Following is used if don't have native, or if fall through - * from above if native doesn't pass checks. - */ - { - static char *buf = NULL; - int len; + if (buf == NULL) { + buf = malloc(VSNP_BUF_SIZE); - if (buf==NULL) { - buf = fc_malloc(VSNP_BUF_SIZE); + if (buf == NULL) { + fprintf(stderr, "Could not allocate %i bytes for vsnprintf() " + "replacement.", VSNP_BUF_SIZE); + exit(1); + } } - #ifdef HAVE_VSNPRINTF - /* This occurs if have native, but didn't pass check: - * may just be that native doesn't give the right return, - * in which case may be slightly safer to use it here: - */ - vsnprintf(buf, VSNP_BUF_SIZE, format, ap); + r = vsnprintf(buf, n, format, ap); #else - vsprintf(buf, format, ap); + r = vsprintf(buf, format, ap); #endif - - /* Check strlen of buf straight away: could be more efficient - not to do this and step through instead (eg if n small and - len long), but useful anyway to get the return value, and - importantly want to abort if vsprintf clobbered the heap! - (Don't just use return from vsprintf since not sure if - that gives the right thing on all platforms?) - Will maintain last char of buffer as null, and use SIZE-2 - as longest string which we can detect as untruncated. - (Don't use freelog() for report since that uses vsnprintf...) - */ - buf[VSNP_BUF_SIZE-1] = '\0'; + buf[VSNP_BUF_SIZE - 1] = '\0'; len = strlen(buf); - if (len >= VSNP_BUF_SIZE-1) { + + if (len >= VSNP_BUF_SIZE - 1) { fprintf(stderr, "Overflow in vsnprintf replacement!" " (buffer size %d) aborting...\n", VSNP_BUF_SIZE); abort(); } - - if (n > len) { - memcpy(str, buf, len+1); /* +1 for terminating null */ + if (n >= len + 1) { + memcpy(str, buf, len+1); return len; } else { memcpy(str, buf, n-1); - str[n-1] = '\0'; - return len; /* truncated */ + str[n - 1] = '\0'; + return -1; } } +#endif } int my_snprintf(char *str, size_t n, const char *format, ...) Index: server/report.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/report.c,v retrieving revision 1.6 diff -u -r1.6 report.c --- server/report.c 2000/10/11 12:56:20 1.6 +++ server/report.c 2001/05/19 22:49:34 @@ -1438,7 +1438,7 @@ len = my_snprintf(genmsg.message, sizeof(genmsg.message), "%s\n%s\n%s", caption, headline, lines); - if (len >= sizeof(genmsg.message)) { + if (len == -1) { freelog(LOG_ERROR, "Message truncated in page_conn_etype()!"); } genmsg.event = event; Index: server/stdinhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v retrieving revision 1.176 diff -u -r1.176 stdinhand.c --- server/stdinhand.c 2001/04/14 11:30:46 1.176 +++ server/stdinhand.c 2001/05/19 22:49:35 @@ -2412,6 +2412,8 @@ cmd_reply_show(horiz_line); len1 = my_snprintf(buf, sizeof(buf), _("%-*s value (min,max) "), OPTION_NAME_SPACE, _("Option")); + if (len1 == -1) + len1 = sizeof(buf) -1; sz_strlcat(buf, _("description")); cmd_reply_show(buf); cmd_reply_show(horiz_line); @@ -2432,12 +2434,16 @@ may_set_option_now(caller,i) ? '+' : ' ', ((*op->value==op->default_value) ? '=' : ' '), *op->value, op->min_value, op->max_value); + if (len == -1) + len = sizeof(buf) - 1; } else { len = my_snprintf(buf, sizeof(buf), "%-*s %c%c\"%s\"", OPTION_NAME_SPACE, op->name, may_set_option_now(caller,i) ? '+' : ' ', ((strcmp(op->svalue, op->default_svalue)==0) ? '=' : ' '), op->svalue); + if (len == -1) + len = sizeof(buf) - 1; } /* Line up the descriptions: */ if(len < len1) {