aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2011-06-16 14:25:42 -0700
committerPaul Eggert2011-06-16 14:25:42 -0700
commit393d71f34cd42b77afe78fbd174f2b1377182232 (patch)
treebb4efa252030d2a65cbf521bf603e9bc403c7c16 /src
parent0cca0a78a4ee6b761c2fd91ee5a6628f23e3368c (diff)
parent4847e3f0a94e3f24b40b060af528cf4b51d788c5 (diff)
downloademacs-393d71f34cd42b77afe78fbd174f2b1377182232.tar.gz
emacs-393d71f34cd42b77afe78fbd174f2b1377182232.zip
Improve buffer-overflow checking (Bug#8873).
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog26
-rw-r--r--src/buffer.h6
-rw-r--r--src/editfns.c27
-rw-r--r--src/fileio.c13
-rw-r--r--src/insdel.c44
-rw-r--r--src/lisp.h1
6 files changed, 60 insertions, 57 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 59fb2d89b24..ae1a00cf173 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,29 @@
12011-06-16 Paul Eggert <eggert@cs.ucla.edu>
2
3 Improve buffer-overflow checking (Bug#8873).
4 * fileio.c (Finsert_file_contents):
5 * insdel.c (insert_from_buffer_1, replace_range, replace_range_2):
6 Remove the old (too-loose) buffer overflow checks.
7 They weren't needed, since make_gap checks for buffer overflow.
8 * insdel.c (make_gap_larger): Catch buffer overflows that were missed.
9 The old code merely checked for Emacs fixnum overflow, and relied
10 on undefined (wraparound) behavior. The new code avoids undefined
11 behavior, and also checks for ptrdiff_t and/or size_t overflow.
12
13 * editfns.c (Finsert_char): Don't dump core with very negative counts.
14 Tune. Don't use wider integers than needed. Don't use alloca.
15 Use a bigger 'string' buffer. Rewrite to avoid 'n > 0' test.
16
17 * insdel.c (replace_range): Fix buf overflow when insbytes < outgoing.
18
19 * insdel.c, lisp.h (buffer_overflow): New function.
20 (insert_from_buffer_1, replace_range, replace_range_2):
21 * insdel.c (make_gap_larger):
22 * editfns.c (Finsert_char):
23 * fileio.c (Finsert_file_contents): Use it, to normalize wording.
24
25 * buffer.h (BUF_BYTES_MAX): Cast to ptrdiff_t so that it's signed.
26
12011-06-15 Paul Eggert <eggert@cs.ucla.edu> 272011-06-15 Paul Eggert <eggert@cs.ucla.edu>
2 28
3 Integer overflow and signedness fixes (Bug#8873). 29 Integer overflow and signedness fixes (Bug#8873).
diff --git a/src/buffer.h b/src/buffer.h
index dc1d62beb00..a13351b5ea6 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -309,8 +309,10 @@ while (0)
309 309
310/* Maximum number of bytes in a buffer. 310/* Maximum number of bytes in a buffer.
311 A buffer cannot contain more bytes than a 1-origin fixnum can represent, 311 A buffer cannot contain more bytes than a 1-origin fixnum can represent,
312 nor can it be so large that C pointer arithmetic stops working. */ 312 nor can it be so large that C pointer arithmetic stops working.
313#define BUF_BYTES_MAX min (MOST_POSITIVE_FIXNUM - 1, min (SIZE_MAX, PTRDIFF_MAX)) 313 The ptrdiff_t cast ensures that this is signed, not unsigned. */
314#define BUF_BYTES_MAX \
315 (ptrdiff_t) min (MOST_POSITIVE_FIXNUM - 1, min (SIZE_MAX, PTRDIFF_MAX))
314 316
315/* Return the address of byte position N in current buffer. */ 317/* Return the address of byte position N in current buffer. */
316 318
diff --git a/src/editfns.c b/src/editfns.c
index 9678d4da6a2..2d736bbc7e2 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -2328,12 +2328,11 @@ The optional third arg INHERIT, if non-nil, says to inherit text properties
2328from adjoining text, if those properties are sticky. */) 2328from adjoining text, if those properties are sticky. */)
2329 (Lisp_Object character, Lisp_Object count, Lisp_Object inherit) 2329 (Lisp_Object character, Lisp_Object count, Lisp_Object inherit)
2330{ 2330{
2331 register char *string; 2331 int i, stringlen;
2332 register EMACS_INT stringlen;
2333 register int i;
2334 register EMACS_INT n; 2332 register EMACS_INT n;
2335 int c, len; 2333 int c, len;
2336 unsigned char str[MAX_MULTIBYTE_LENGTH]; 2334 unsigned char str[MAX_MULTIBYTE_LENGTH];
2335 char string[4000];
2337 2336
2338 CHECK_CHARACTER (character); 2337 CHECK_CHARACTER (character);
2339 CHECK_NUMBER (count); 2338 CHECK_NUMBER (count);
@@ -2343,16 +2342,15 @@ from adjoining text, if those properties are sticky. */)
2343 len = CHAR_STRING (c, str); 2342 len = CHAR_STRING (c, str);
2344 else 2343 else
2345 str[0] = c, len = 1; 2344 str[0] = c, len = 1;
2345 if (XINT (count) <= 0)
2346 return Qnil;
2346 if (BUF_BYTES_MAX / len < XINT (count)) 2347 if (BUF_BYTES_MAX / len < XINT (count))
2347 error ("Maximum buffer size would be exceeded"); 2348 buffer_overflow ();
2348 n = XINT (count) * len; 2349 n = XINT (count) * len;
2349 if (n <= 0) 2350 stringlen = min (n, sizeof string - sizeof string % len);
2350 return Qnil;
2351 stringlen = min (n, 256 * len);
2352 string = (char *) alloca (stringlen);
2353 for (i = 0; i < stringlen; i++) 2351 for (i = 0; i < stringlen; i++)
2354 string[i] = str[i % len]; 2352 string[i] = str[i % len];
2355 while (n >= stringlen) 2353 while (n > stringlen)
2356 { 2354 {
2357 QUIT; 2355 QUIT;
2358 if (!NILP (inherit)) 2356 if (!NILP (inherit))
@@ -2361,13 +2359,10 @@ from adjoining text, if those properties are sticky. */)
2361 insert (string, stringlen); 2359 insert (string, stringlen);
2362 n -= stringlen; 2360 n -= stringlen;
2363 } 2361 }
2364 if (n > 0) 2362 if (!NILP (inherit))
2365 { 2363 insert_and_inherit (string, n);
2366 if (!NILP (inherit)) 2364 else
2367 insert_and_inherit (string, n); 2365 insert (string, n);
2368 else
2369 insert (string, n);
2370 }
2371 return Qnil; 2366 return Qnil;
2372} 2367}
2373 2368
diff --git a/src/fileio.c b/src/fileio.c
index fd5277cbd59..dd34872c263 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -3264,7 +3264,7 @@ variable `last-coding-system-used' to the coding system actually used. */)
3264 platform that allows file sizes greater than the maximum off_t value. */ 3264 platform that allows file sizes greater than the maximum off_t value. */
3265 if (! not_regular 3265 if (! not_regular
3266 && ! (0 <= st.st_size && st.st_size <= BUF_BYTES_MAX)) 3266 && ! (0 <= st.st_size && st.st_size <= BUF_BYTES_MAX))
3267 error ("Maximum buffer size exceeded"); 3267 buffer_overflow ();
3268 3268
3269 /* Prevent redisplay optimizations. */ 3269 /* Prevent redisplay optimizations. */
3270 current_buffer->clip_changed = 1; 3270 current_buffer->clip_changed = 1;
@@ -3800,16 +3800,7 @@ variable `last-coding-system-used' to the coding system actually used. */)
3800 } 3800 }
3801 3801
3802 if (! not_regular) 3802 if (! not_regular)
3803 { 3803 total = XINT (end) - XINT (beg);
3804 register Lisp_Object temp;
3805
3806 total = XINT (end) - XINT (beg);
3807
3808 /* Make sure point-max won't overflow after this insertion. */
3809 XSETINT (temp, total);
3810 if (total != XINT (temp))
3811 error ("Maximum buffer size exceeded");
3812 }
3813 else 3804 else
3814 /* For a special file, all we can do is guess. */ 3805 /* For a special file, all we can do is guess. */
3815 total = READ_BUF_SIZE; 3806 total = READ_BUF_SIZE;
diff --git a/src/insdel.c b/src/insdel.c
index c0cccc65d6a..bc95e3ad9e8 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -391,6 +391,12 @@ adjust_markers_for_replace (EMACS_INT from, EMACS_INT from_byte,
391} 391}
392 392
393 393
394void
395buffer_overflow (void)
396{
397 error ("Maximum buffer size exceeded");
398}
399
394/* Make the gap NBYTES_ADDED bytes longer. */ 400/* Make the gap NBYTES_ADDED bytes longer. */
395 401
396static void 402static void
@@ -400,16 +406,16 @@ make_gap_larger (EMACS_INT nbytes_added)
400 EMACS_INT real_gap_loc; 406 EMACS_INT real_gap_loc;
401 EMACS_INT real_gap_loc_byte; 407 EMACS_INT real_gap_loc_byte;
402 EMACS_INT old_gap_size; 408 EMACS_INT old_gap_size;
409 EMACS_INT current_size = Z_BYTE - BEG_BYTE + GAP_SIZE;
410 enum { enough_for_a_while = 2000 };
403 411
404 /* If we have to get more space, get enough to last a while. */ 412 if (BUF_BYTES_MAX - current_size < nbytes_added)
405 nbytes_added += 2000; 413 buffer_overflow ();
406 414
407 { EMACS_INT total_size = Z_BYTE - BEG_BYTE + GAP_SIZE + nbytes_added; 415 /* If we have to get more space, get enough to last a while;
408 if (total_size < 0 416 but do not exceed the maximum buffer size. */
409 /* Don't allow a buffer size that won't fit in a Lisp integer. */ 417 nbytes_added = min (nbytes_added + enough_for_a_while,
410 || total_size != XINT (make_number (total_size))) 418 BUF_BYTES_MAX - current_size);
411 error ("Buffer exceeds maximum size");
412 }
413 419
414 enlarge_buffer_text (current_buffer, nbytes_added); 420 enlarge_buffer_text (current_buffer, nbytes_added);
415 421
@@ -1063,7 +1069,6 @@ static void
1063insert_from_buffer_1 (struct buffer *buf, 1069insert_from_buffer_1 (struct buffer *buf,
1064 EMACS_INT from, EMACS_INT nchars, int inherit) 1070 EMACS_INT from, EMACS_INT nchars, int inherit)
1065{ 1071{
1066 register Lisp_Object temp;
1067 EMACS_INT chunk, chunk_expanded; 1072 EMACS_INT chunk, chunk_expanded;
1068 EMACS_INT from_byte = buf_charpos_to_bytepos (buf, from); 1073 EMACS_INT from_byte = buf_charpos_to_bytepos (buf, from);
1069 EMACS_INT to_byte = buf_charpos_to_bytepos (buf, from + nchars); 1074 EMACS_INT to_byte = buf_charpos_to_bytepos (buf, from + nchars);
@@ -1102,11 +1107,6 @@ insert_from_buffer_1 (struct buffer *buf,
1102 outgoing_nbytes = outgoing_before_gap + outgoing_after_gap; 1107 outgoing_nbytes = outgoing_before_gap + outgoing_after_gap;
1103 } 1108 }
1104 1109
1105 /* Make sure point-max won't overflow after this insertion. */
1106 XSETINT (temp, outgoing_nbytes + Z);
1107 if (outgoing_nbytes + Z != XINT (temp))
1108 error ("Maximum buffer size exceeded");
1109
1110 /* Do this before moving and increasing the gap, 1110 /* Do this before moving and increasing the gap,
1111 because the before-change hooks might move the gap 1111 because the before-change hooks might move the gap
1112 or make it smaller. */ 1112 or make it smaller. */
@@ -1303,7 +1303,6 @@ replace_range (EMACS_INT from, EMACS_INT to, Lisp_Object new,
1303 EMACS_INT insbytes = SBYTES (new); 1303 EMACS_INT insbytes = SBYTES (new);
1304 EMACS_INT from_byte, to_byte; 1304 EMACS_INT from_byte, to_byte;
1305 EMACS_INT nbytes_del, nchars_del; 1305 EMACS_INT nbytes_del, nchars_del;
1306 register Lisp_Object temp;
1307 struct gcpro gcpro1; 1306 struct gcpro gcpro1;
1308 INTERVAL intervals; 1307 INTERVAL intervals;
1309 EMACS_INT outgoing_insbytes = insbytes; 1308 EMACS_INT outgoing_insbytes = insbytes;
@@ -1347,11 +1346,6 @@ replace_range (EMACS_INT from, EMACS_INT to, Lisp_Object new,
1347 outgoing_insbytes 1346 outgoing_insbytes
1348 = count_size_as_multibyte (SDATA (new), insbytes); 1347 = count_size_as_multibyte (SDATA (new), insbytes);
1349 1348
1350 /* Make sure point-max won't overflow after this insertion. */
1351 XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
1352 if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
1353 error ("Maximum buffer size exceeded");
1354
1355 GCPRO1 (new); 1349 GCPRO1 (new);
1356 1350
1357 /* Make sure the gap is somewhere in or next to what we are deleting. */ 1351 /* 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 if (Z - GPT < END_UNCHANGED) 1377 if (Z - GPT < END_UNCHANGED)
1384 END_UNCHANGED = Z - GPT; 1378 END_UNCHANGED = Z - GPT;
1385 1379
1386 if (GAP_SIZE < insbytes) 1380 if (GAP_SIZE < outgoing_insbytes)
1387 make_gap (insbytes - GAP_SIZE); 1381 make_gap (outgoing_insbytes - GAP_SIZE);
1388 1382
1389 /* Copy the string text into the buffer, perhaps converting 1383 /* Copy the string text into the buffer, perhaps converting
1390 between single-byte and multibyte. */ 1384 between single-byte and multibyte. */
@@ -1482,7 +1476,6 @@ replace_range_2 (EMACS_INT from, EMACS_INT from_byte,
1482 int markers) 1476 int markers)
1483{ 1477{
1484 EMACS_INT nbytes_del, nchars_del; 1478 EMACS_INT nbytes_del, nchars_del;
1485 Lisp_Object temp;
1486 1479
1487 CHECK_MARKERS (); 1480 CHECK_MARKERS ();
1488 1481
@@ -1492,11 +1485,6 @@ replace_range_2 (EMACS_INT from, EMACS_INT from_byte,
1492 if (nbytes_del <= 0 && insbytes == 0) 1485 if (nbytes_del <= 0 && insbytes == 0)
1493 return; 1486 return;
1494 1487
1495 /* Make sure point-max won't overflow after this insertion. */
1496 XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
1497 if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
1498 error ("Maximum buffer size exceeded");
1499
1500 /* Make sure the gap is somewhere in or next to what we are deleting. */ 1488 /* Make sure the gap is somewhere in or next to what we are deleting. */
1501 if (from > GPT) 1489 if (from > GPT)
1502 gap_right (from, from_byte); 1490 gap_right (from, from_byte);
diff --git a/src/lisp.h b/src/lisp.h
index 83534e55433..75827deda1a 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2635,6 +2635,7 @@ extern void init_image (void);
2635extern Lisp_Object Qinhibit_modification_hooks; 2635extern Lisp_Object Qinhibit_modification_hooks;
2636extern void move_gap (EMACS_INT); 2636extern void move_gap (EMACS_INT);
2637extern void move_gap_both (EMACS_INT, EMACS_INT); 2637extern void move_gap_both (EMACS_INT, EMACS_INT);
2638extern void buffer_overflow (void) NO_RETURN;
2638extern void make_gap (EMACS_INT); 2639extern void make_gap (EMACS_INT);
2639extern EMACS_INT copy_text (const unsigned char *, unsigned char *, 2640extern EMACS_INT copy_text (const unsigned char *, unsigned char *,
2640 EMACS_INT, int, int); 2641 EMACS_INT, int, int);