Commit 393d71f3 authored by Paul Eggert's avatar Paul Eggert
Browse files

Improve buffer-overflow checking (Bug#8873).

parents 0cca0a78 4847e3f0
2011-06-16 Paul Eggert <eggert@cs.ucla.edu>
Improve buffer-overflow checking (Bug#8873).
* fileio.c (Finsert_file_contents):
* insdel.c (insert_from_buffer_1, replace_range, replace_range_2):
Remove the old (too-loose) buffer overflow checks.
They weren't needed, since make_gap checks for buffer overflow.
* insdel.c (make_gap_larger): Catch buffer overflows that were missed.
The old code merely checked for Emacs fixnum overflow, and relied
on undefined (wraparound) behavior. The new code avoids undefined
behavior, and also checks for ptrdiff_t and/or size_t overflow.
* editfns.c (Finsert_char): Don't dump core with very negative counts.
Tune. Don't use wider integers than needed. Don't use alloca.
Use a bigger 'string' buffer. Rewrite to avoid 'n > 0' test.
* insdel.c (replace_range): Fix buf overflow when insbytes < outgoing.
* insdel.c, lisp.h (buffer_overflow): New function.
(insert_from_buffer_1, replace_range, replace_range_2):
* insdel.c (make_gap_larger):
* editfns.c (Finsert_char):
* fileio.c (Finsert_file_contents): Use it, to normalize wording.
* buffer.h (BUF_BYTES_MAX): Cast to ptrdiff_t so that it's signed.
2011-06-15 Paul Eggert <eggert@cs.ucla.edu> 2011-06-15 Paul Eggert <eggert@cs.ucla.edu>
Integer overflow and signedness fixes (Bug#8873). Integer overflow and signedness fixes (Bug#8873).
......
...@@ -309,8 +309,10 @@ while (0) ...@@ -309,8 +309,10 @@ while (0)
/* Maximum number of bytes in a buffer. /* Maximum number of bytes in a buffer.
A buffer cannot contain more bytes than a 1-origin fixnum can represent, A buffer cannot contain more bytes than a 1-origin fixnum can represent,
nor can it be so large that C pointer arithmetic stops working. */ nor can it be so large that C pointer arithmetic stops working.
#define BUF_BYTES_MAX min (MOST_POSITIVE_FIXNUM - 1, min (SIZE_MAX, PTRDIFF_MAX)) The ptrdiff_t cast ensures that this is signed, not unsigned. */
#define BUF_BYTES_MAX \
(ptrdiff_t) min (MOST_POSITIVE_FIXNUM - 1, min (SIZE_MAX, PTRDIFF_MAX))
/* Return the address of byte position N in current buffer. */ /* Return the address of byte position N in current buffer. */
......
...@@ -2328,12 +2328,11 @@ The optional third arg INHERIT, if non-nil, says to inherit text properties ...@@ -2328,12 +2328,11 @@ The optional third arg INHERIT, if non-nil, says to inherit text properties
from adjoining text, if those properties are sticky. */) from adjoining text, if those properties are sticky. */)
(Lisp_Object character, Lisp_Object count, Lisp_Object inherit) (Lisp_Object character, Lisp_Object count, Lisp_Object inherit)
{ {
register char *string; int i, stringlen;
register EMACS_INT stringlen;
register int i;
register EMACS_INT n; register EMACS_INT n;
int c, len; int c, len;
unsigned char str[MAX_MULTIBYTE_LENGTH]; unsigned char str[MAX_MULTIBYTE_LENGTH];
char string[4000];
CHECK_CHARACTER (character); CHECK_CHARACTER (character);
CHECK_NUMBER (count); CHECK_NUMBER (count);
...@@ -2343,16 +2342,15 @@ from adjoining text, if those properties are sticky. */) ...@@ -2343,16 +2342,15 @@ from adjoining text, if those properties are sticky. */)
len = CHAR_STRING (c, str); len = CHAR_STRING (c, str);
else else
str[0] = c, len = 1; str[0] = c, len = 1;
if (XINT (count) <= 0)
return Qnil;
if (BUF_BYTES_MAX / len < XINT (count)) if (BUF_BYTES_MAX / len < XINT (count))
error ("Maximum buffer size would be exceeded"); buffer_overflow ();
n = XINT (count) * len; n = XINT (count) * len;
if (n <= 0) stringlen = min (n, sizeof string - sizeof string % len);
return Qnil;
stringlen = min (n, 256 * len);
string = (char *) alloca (stringlen);
for (i = 0; i < stringlen; i++) for (i = 0; i < stringlen; i++)
string[i] = str[i % len]; string[i] = str[i % len];
while (n >= stringlen) while (n > stringlen)
{ {
QUIT; QUIT;
if (!NILP (inherit)) if (!NILP (inherit))
...@@ -2361,13 +2359,10 @@ from adjoining text, if those properties are sticky. */) ...@@ -2361,13 +2359,10 @@ from adjoining text, if those properties are sticky. */)
insert (string, stringlen); insert (string, stringlen);
n -= stringlen; n -= stringlen;
} }
if (n > 0) if (!NILP (inherit))
{ insert_and_inherit (string, n);
if (!NILP (inherit)) else
insert_and_inherit (string, n); insert (string, n);
else
insert (string, n);
}
return Qnil; return Qnil;
} }
......
...@@ -3264,7 +3264,7 @@ variable `last-coding-system-used' to the coding system actually used. */) ...@@ -3264,7 +3264,7 @@ variable `last-coding-system-used' to the coding system actually used. */)
platform that allows file sizes greater than the maximum off_t value. */ platform that allows file sizes greater than the maximum off_t value. */
if (! not_regular if (! not_regular
&& ! (0 <= st.st_size && st.st_size <= BUF_BYTES_MAX)) && ! (0 <= st.st_size && st.st_size <= BUF_BYTES_MAX))
error ("Maximum buffer size exceeded"); buffer_overflow ();
/* Prevent redisplay optimizations. */ /* Prevent redisplay optimizations. */
current_buffer->clip_changed = 1; current_buffer->clip_changed = 1;
...@@ -3800,16 +3800,7 @@ variable `last-coding-system-used' to the coding system actually used. */) ...@@ -3800,16 +3800,7 @@ variable `last-coding-system-used' to the coding system actually used. */)
} }
if (! not_regular) if (! not_regular)
{ total = XINT (end) - XINT (beg);
register Lisp_Object temp;
total = XINT (end) - XINT (beg);
/* Make sure point-max won't overflow after this insertion. */
XSETINT (temp, total);
if (total != XINT (temp))
error ("Maximum buffer size exceeded");
}
else else
/* For a special file, all we can do is guess. */ /* For a special file, all we can do is guess. */
total = READ_BUF_SIZE; total = READ_BUF_SIZE;
......
...@@ -391,6 +391,12 @@ adjust_markers_for_replace (EMACS_INT from, EMACS_INT from_byte, ...@@ -391,6 +391,12 @@ adjust_markers_for_replace (EMACS_INT from, EMACS_INT from_byte,
} }
void
buffer_overflow (void)
{
error ("Maximum buffer size exceeded");
}
/* Make the gap NBYTES_ADDED bytes longer. */ /* Make the gap NBYTES_ADDED bytes longer. */
static void static void
...@@ -400,16 +406,16 @@ make_gap_larger (EMACS_INT nbytes_added) ...@@ -400,16 +406,16 @@ make_gap_larger (EMACS_INT nbytes_added)
EMACS_INT real_gap_loc; EMACS_INT real_gap_loc;
EMACS_INT real_gap_loc_byte; EMACS_INT real_gap_loc_byte;
EMACS_INT old_gap_size; EMACS_INT old_gap_size;
EMACS_INT current_size = Z_BYTE - BEG_BYTE + GAP_SIZE;
enum { enough_for_a_while = 2000 };
/* If we have to get more space, get enough to last a while. */ if (BUF_BYTES_MAX - current_size < nbytes_added)
nbytes_added += 2000; buffer_overflow ();
{ EMACS_INT total_size = Z_BYTE - BEG_BYTE + GAP_SIZE + nbytes_added; /* If we have to get more space, get enough to last a while;
if (total_size < 0 but do not exceed the maximum buffer size. */
/* Don't allow a buffer size that won't fit in a Lisp integer. */ nbytes_added = min (nbytes_added + enough_for_a_while,
|| total_size != XINT (make_number (total_size))) BUF_BYTES_MAX - current_size);
error ("Buffer exceeds maximum size");
}
enlarge_buffer_text (current_buffer, nbytes_added); enlarge_buffer_text (current_buffer, nbytes_added);
...@@ -1063,7 +1069,6 @@ static void ...@@ -1063,7 +1069,6 @@ static void
insert_from_buffer_1 (struct buffer *buf, insert_from_buffer_1 (struct buffer *buf,
EMACS_INT from, EMACS_INT nchars, int inherit) EMACS_INT from, EMACS_INT nchars, int inherit)
{ {
register Lisp_Object temp;
EMACS_INT chunk, chunk_expanded; EMACS_INT chunk, chunk_expanded;
EMACS_INT from_byte = buf_charpos_to_bytepos (buf, from); EMACS_INT from_byte = buf_charpos_to_bytepos (buf, from);
EMACS_INT to_byte = buf_charpos_to_bytepos (buf, from + nchars); EMACS_INT to_byte = buf_charpos_to_bytepos (buf, from + nchars);
...@@ -1102,11 +1107,6 @@ insert_from_buffer_1 (struct buffer *buf, ...@@ -1102,11 +1107,6 @@ insert_from_buffer_1 (struct buffer *buf,
outgoing_nbytes = outgoing_before_gap + outgoing_after_gap; outgoing_nbytes = outgoing_before_gap + outgoing_after_gap;
} }
/* Make sure point-max won't overflow after this insertion. */
XSETINT (temp, outgoing_nbytes + Z);
if (outgoing_nbytes + Z != XINT (temp))
error ("Maximum buffer size exceeded");
/* Do this before moving and increasing the gap, /* Do this before moving and increasing the gap,
because the before-change hooks might move the gap because the before-change hooks might move the gap
or make it smaller. */ or make it smaller. */
...@@ -1303,7 +1303,6 @@ replace_range (EMACS_INT from, EMACS_INT to, Lisp_Object new, ...@@ -1303,7 +1303,6 @@ replace_range (EMACS_INT from, EMACS_INT to, Lisp_Object new,
EMACS_INT insbytes = SBYTES (new); EMACS_INT insbytes = SBYTES (new);
EMACS_INT from_byte, to_byte; EMACS_INT from_byte, to_byte;
EMACS_INT nbytes_del, nchars_del; EMACS_INT nbytes_del, nchars_del;
register Lisp_Object temp;
struct gcpro gcpro1; struct gcpro gcpro1;
INTERVAL intervals; INTERVAL intervals;
EMACS_INT outgoing_insbytes = insbytes; EMACS_INT outgoing_insbytes = insbytes;
...@@ -1347,11 +1346,6 @@ replace_range (EMACS_INT from, EMACS_INT to, Lisp_Object new, ...@@ -1347,11 +1346,6 @@ replace_range (EMACS_INT from, EMACS_INT to, Lisp_Object new,
outgoing_insbytes outgoing_insbytes
= count_size_as_multibyte (SDATA (new), insbytes); = count_size_as_multibyte (SDATA (new), insbytes);
/* Make sure point-max won't overflow after this insertion. */
XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
error ("Maximum buffer size exceeded");
GCPRO1 (new); GCPRO1 (new);
/* Make sure the gap is somewhere in or next to what we are deleting. */ /* Make sure the gap is somewhere in or next to what we are deleting. */
...@@ -1383,8 +1377,8 @@ replace_range (EMACS_INT from, EMACS_INT to, Lisp_Object new, ...@@ -1383,8 +1377,8 @@ replace_range (EMACS_INT from, EMACS_INT to, Lisp_Object new,
if (Z - GPT < END_UNCHANGED) if (Z - GPT < END_UNCHANGED)
END_UNCHANGED = Z - GPT; END_UNCHANGED = Z - GPT;
if (GAP_SIZE < insbytes) if (GAP_SIZE < outgoing_insbytes)
make_gap (insbytes - GAP_SIZE); make_gap (outgoing_insbytes - GAP_SIZE);
/* Copy the string text into the buffer, perhaps converting /* Copy the string text into the buffer, perhaps converting
between single-byte and multibyte. */ between single-byte and multibyte. */
...@@ -1482,7 +1476,6 @@ replace_range_2 (EMACS_INT from, EMACS_INT from_byte, ...@@ -1482,7 +1476,6 @@ replace_range_2 (EMACS_INT from, EMACS_INT from_byte,
int markers) int markers)
{ {
EMACS_INT nbytes_del, nchars_del; EMACS_INT nbytes_del, nchars_del;
Lisp_Object temp;
CHECK_MARKERS (); CHECK_MARKERS ();
...@@ -1492,11 +1485,6 @@ replace_range_2 (EMACS_INT from, EMACS_INT from_byte, ...@@ -1492,11 +1485,6 @@ replace_range_2 (EMACS_INT from, EMACS_INT from_byte,
if (nbytes_del <= 0 && insbytes == 0) if (nbytes_del <= 0 && insbytes == 0)
return; return;
/* Make sure point-max won't overflow after this insertion. */
XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
error ("Maximum buffer size exceeded");
/* Make sure the gap is somewhere in or next to what we are deleting. */ /* Make sure the gap is somewhere in or next to what we are deleting. */
if (from > GPT) if (from > GPT)
gap_right (from, from_byte); gap_right (from, from_byte);
......
...@@ -2635,6 +2635,7 @@ extern void init_image (void); ...@@ -2635,6 +2635,7 @@ extern void init_image (void);
extern Lisp_Object Qinhibit_modification_hooks; extern Lisp_Object Qinhibit_modification_hooks;
extern void move_gap (EMACS_INT); extern void move_gap (EMACS_INT);
extern void move_gap_both (EMACS_INT, EMACS_INT); extern void move_gap_both (EMACS_INT, EMACS_INT);
extern void buffer_overflow (void) NO_RETURN;
extern void make_gap (EMACS_INT); extern void make_gap (EMACS_INT);
extern EMACS_INT copy_text (const unsigned char *, unsigned char *, extern EMACS_INT copy_text (const unsigned char *, unsigned char *,
EMACS_INT, int, int); EMACS_INT, int, int);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment