? typescript Index: common/ioz.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/ioz.c,v retrieving revision 1.3 diff -u -r1.3 ioz.c --- ioz.c 2000/08/14 12:42:04 1.3 +++ ioz.c 2000/11/19 13:04:42 @@ -211,10 +211,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()"); + retval = gzwrite(fp->u.zlib, buffer, (unsigned int)strlen(buffer)); } break; Index: common/support.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/support.c,v retrieving revision 1.10 diff -u -r1.10 support.c --- support.c 2000/09/03 03:18:17 1.10 +++ support.c 2000/11/19 13:04:42 @@ -242,193 +242,48 @@ #endif } +/* A vsnprintf() wrapper that 1) normalises the return value and 2) + falls back to vsprintf() with a big buffer if vsnprintf() isn't + available. */ -#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); -#if 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 - - Parameter n specifies the maximum number of characters to produce. - This includes the trailing null, so n should be the actual number - of characters allocated (or sizeof for char array). If truncation - occurs, the result will still be null-terminated. (I'm not sure - whether all native vsnprintf() functions null-terminate on - truncation; this does so even if calls native function.) - - Return value: if there is no truncation, returns the number of - characters printed, not including the trailing null. If truncation - does occur, returns the number of characters which would have been - produced without truncation. - (Linux man page says returns -1 on truncation, but glibc seems to - do as above nevertheless; check_native_vsnprintf() above tests this.) - - [glibc is correct. Viz. - - PRINTF(3) Linux Programmer's Manual PRINTF(3) - - (Thus until glibc 2.0.6. Since glibc 2.1 these functions follow the - C99 standard and return the number of characters (excluding the - trailing '\0') which would have been written to the final string if - enough space had been available.)] - - The method is simply to malloc (first time called) a big internal - buffer, longer than any result is likely to be (for non-malicious - usage), then vsprintf to that buffer, and copy the appropriate - number of characters to the destination. Thus, this is not 100% - safe. But somewhat safe, and at least safer than using raw snprintf! - :-) (And of course if you have the native version it is safe.) - - Before rushing to provide a 100% safe replacement version, consider - the following advantages of this method: - - - It is very simple, so not likely to have many bugs (other than - arguably the core design bug regarding absolute safety), nor need - maintenance. - - - It uses native vsprintf() (which is required), thus exactly - duplicates the native format-string parsing/conversions. - - - It is *very* portable. Eg, it does not require mprotect(), nor - does it do any of its own parsing of the format string, nor use - any tricks to go through the va_list twice. - -***********************************************************************/ - /* buffer size: "64k should be big enough for anyone" ;-) */ -#define VSNP_BUF_SIZE (64*1024) +#define VSNP_BUF_SIZE (64 * 1024) int my_vsnprintf(char *str, size_t n, const char *format, va_list ap) { + int ret; /* This may be overzealous, but I suspect any triggering of these - * to be bugs. (Do this even if call native function.) + * to be bugs. */ assert(str); - assert(n>0); + assert(n > 0); assert(format); #ifdef HAVE_VSNPRINTF - { - static int native_is_ok = -1; /* set to 0 or 1 on first call */ + ret = vsnprintf(str, n, format, ap); - if (native_is_ok == -1) { - native_is_ok = check_native_vsnprintf(); - } - - 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; + /* Enforce pre-C99 return values. */ + if (ret >= n) + ret = -1; - if (buf==NULL) { - buf = fc_malloc(VSNP_BUF_SIZE); - } +#else /* Are there still any such systems around? */ + { + static char *buffer = NULL; + + if (!buffer) + buffer = fc_malloc(VSNP_BUF_SIZE); + + ret = vsprintf(buffer, format, ap); + assert(ret < VSNP_BUF_SIZE); -#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); -#else - vsprintf(buf, format, ap); + memcpy(str, buffer, ret + 1); + } #endif + + /* Make sure the result is NUL-terminated. */ + str[n-1] = '\0'; - /* 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'; - len = strlen(buf); - 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 */ - return len; - } else { - memcpy(str, buf, n-1); - str[n-1] = '\0'; - return len; /* truncated */ - } - } + return ret; } 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 --- report.c 2000/10/11 12:56:20 1.6 +++ report.c 2000/11/19 13:04:43 @@ -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.167 diff -u -r1.167 stdinhand.c --- stdinhand.c 2000/09/25 01:26:38 1.167 +++ stdinhand.c 2000/11/19 13:04:45 @@ -2392,6 +2392,9 @@ 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); @@ -2418,6 +2421,8 @@ 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) {