martin 98/05/07 00:47:34
Modified: src/ap ap_snprintf.c Log: Avoid core dumps for bogus ap_snprintf() format strings by using more defensive approach: never allow patching a prefix char in front of a constant string (or in front of char_buf); delimit strchr() to not scan past the generated string; Add 'h' modifier for compatibility reasons with other printf()s. Revision Changes Path 1.21 +15 -6 apache-1.3/src/ap/ap_snprintf.c Index: ap_snprintf.c =================================================================== RCS file: /home/cvs/apache-1.3/src/ap/ap_snprintf.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -u -r1.20 -r1.21 --- ap_snprintf.c 1998/05/06 19:49:46 1.20 +++ ap_snprintf.c 1998/05/07 07:47:33 1.21 @@ -677,8 +677,11 @@ is_long = YES; fmt++; } - else + else { + if (*fmt == 'h') /* "short" backward compatibility */ + ++fmt; is_long = NO; + } /* * Argument extraction and printing. @@ -772,7 +775,9 @@ case 'e': case 'E': fp_num = va_arg(ap, double); - + /* + * * We use &num_buf[ 1 ], so that we have room for the sign + */ s = conv_fp(*fmt, fp_num, alternate_form, (adjust_precision == NO) ? FLOAT_DIGITS : precision, &is_negative, &num_buf[1], &s_len); @@ -804,8 +809,10 @@ s_len = strlen(s); - if (alternate_form && (q = strchr(s, '.')) == NULL) + if (alternate_form && (q = strchr(s, '.')) == NULL) { s[s_len++] = '.'; + s[s_len] = '\0'; /* delimit for following strchr() */ + } if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) *q = 'E'; break; @@ -851,6 +858,7 @@ else { s = "%p"; s_len = 2; + prefix_char = NUL; } pad_char = ' '; break; @@ -900,6 +908,7 @@ default: s = "bogus %p"; s_len = 8; + prefix_char = NUL; break; } break; @@ -931,15 +940,15 @@ break; } - if (prefix_char != NUL) { + if (prefix_char != NUL && s != S_NULL & s != char_buf) { *--s = prefix_char; s_len++; } if (adjust_width && adjust == RIGHT && min_width > s_len) { if (pad_char == '0' && prefix_char != NUL) { - INS_CHAR(*s, sp, bep, cc) - s++; + INS_CHAR(*s, sp, bep, cc); + s++; s_len--; min_width--; }