aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGerd Moellmann2000-12-14 16:18:54 +0000
committerGerd Moellmann2000-12-14 16:18:54 +0000
commita432bfe5e7c4650bda0d1400918dbf8f6082b29e (patch)
tree36e201cde56008391a0409f7d0f3e33749ddfdfe /src
parent0b750d70055fc8a04dd08de64a7c88ae72352ba6 (diff)
downloademacs-a432bfe5e7c4650bda0d1400918dbf8f6082b29e.tar.gz
emacs-a432bfe5e7c4650bda0d1400918dbf8f6082b29e.zip
(Fformat): Prevent a buffer overrun when the format
specifies a precision.
Diffstat (limited to 'src')
-rw-r--r--src/editfns.c57
1 files changed, 45 insertions, 12 deletions
diff --git a/src/editfns.c b/src/editfns.c
index e83e92f1396..1c8bc4c007d 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3118,17 +3118,45 @@ Use %% to put a single % into the output.")
3118 while (format != end) 3118 while (format != end)
3119 if (*format++ == '%') 3119 if (*format++ == '%')
3120 { 3120 {
3121 int minlen, thissize = 0; 3121 int thissize = 0;
3122 unsigned char *this_format_start = format - 1; 3122 unsigned char *this_format_start = format - 1;
3123 int field_width, precision;
3123 3124
3124 /* Process a numeric arg and skip it. */ 3125 /* General format specifications look like
3125 minlen = atoi (format);
3126 if (minlen < 0)
3127 minlen = - minlen;
3128 3126
3129 while ((*format >= '0' && *format <= '9') 3127 '%' [flags] [field-width] [precision] format
3130 || *format == '-' || *format == ' ' || *format == '.') 3128
3131 format++; 3129 where
3130
3131 flags ::= [#-* 0]+
3132 field-width ::= [0-9]+
3133 precision ::= '.' [0-9]*
3134
3135 If a field-width is specified, it specifies to which width
3136 the output should be padded with blanks, iff the output
3137 string is shorter than field-width.
3138
3139 if precision is specified, it specifies the number of
3140 digits to print after the '.' for floats, or the max.
3141 number of chars to print from a string. */
3142
3143 precision = field_width = 0;
3144
3145 while (index ("-*# 0", *format))
3146 ++format;
3147
3148 if (*format >= '0' && *format <= '9')
3149 {
3150 for (field_width = 0; *format >= '0' && *format <= '9'; ++format)
3151 field_width = 10 * field_width + *format - '0';
3152 }
3153
3154 if (*format == '.')
3155 {
3156 ++format;
3157 for (precision = 0; *format >= '0' && *format <= '9'; ++format)
3158 precision = 10 * precision + *format - '0';
3159 }
3132 3160
3133 if (format - this_format_start + 1 > longest_format) 3161 if (format - this_format_start + 1 > longest_format)
3134 longest_format = format - this_format_start + 1; 3162 longest_format = format - this_format_start + 1;
@@ -3204,7 +3232,11 @@ Use %% to put a single % into the output.")
3204 { 3232 {
3205 if (! (*format == 'e' || *format == 'f' || *format == 'g')) 3233 if (! (*format == 'e' || *format == 'f' || *format == 'g'))
3206 args[n] = Ftruncate (args[n], Qnil); 3234 args[n] = Ftruncate (args[n], Qnil);
3207 thissize = 200; 3235
3236 /* Note that we're using sprintf to print floats,
3237 so we have to take into account what that function
3238 prints. */
3239 thissize = 200 + precision;
3208 } 3240 }
3209 else 3241 else
3210 { 3242 {
@@ -3220,9 +3252,7 @@ Use %% to put a single % into the output.")
3220 goto string; 3252 goto string;
3221 } 3253 }
3222 3254
3223 if (thissize < minlen) 3255 thissize = max (field_width, thissize);
3224 thissize = minlen;
3225
3226 total += thissize + 4; 3256 total += thissize + 4;
3227 } 3257 }
3228 3258
@@ -3374,6 +3404,9 @@ Use %% to put a single % into the output.")
3374 *p++ = *format++, nchars++; 3404 *p++ = *format++, nchars++;
3375 } 3405 }
3376 3406
3407 if (p > buf + total + 1)
3408 abort ();
3409
3377 if (maybe_combine_byte) 3410 if (maybe_combine_byte)
3378 nchars = multibyte_chars_in_text (buf, p - buf); 3411 nchars = multibyte_chars_in_text (buf, p - buf);
3379 val = make_specified_string (buf, nchars, p - buf, multibyte); 3412 val = make_specified_string (buf, nchars, p - buf, multibyte);