aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2011-06-03 19:49:51 -0700
committerPaul Eggert2011-06-03 19:49:51 -0700
commitedaa182249601b0f7ee36f9863243b6919943982 (patch)
tree1e399289df34c433f0471efdfb8a6da4ab05ac25 /src
parentc6c3615fb23e438701da089110b645fc771f8087 (diff)
downloademacs-edaa182249601b0f7ee36f9863243b6919943982.tar.gz
emacs-edaa182249601b0f7ee36f9863243b6919943982.zip
Check for buffer and string overflow more precisely.
* buffer.h (BUF_BYTES_MAX): New macro. * lisp.h (STRING_BYTES_MAX): New macro. * alloc.c (Fmake_string): * character.c (string_escape_byte8): * coding.c (coding_alloc_by_realloc): * doprnt.c (doprnt): * editfns.c (Fformat): * eval.c (verror): Use STRING_BYTES_MAX, not MOST_POSITIVE_FIXNUM, since they may not be the same number. * editfns.c (Finsert_char): * fileio.c (Finsert_file_contents): Likewise for BUF_BYTES_MAX.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog15
-rw-r--r--src/alloc.c2
-rw-r--r--src/buffer.h5
-rw-r--r--src/character.c4
-rw-r--r--src/coding.c4
-rw-r--r--src/doprnt.c4
-rw-r--r--src/editfns.c4
-rw-r--r--src/eval.c2
-rw-r--r--src/fileio.c2
-rw-r--r--src/lisp.h6
10 files changed, 37 insertions, 11 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 8333bf2dedd..374790b51f6 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,20 @@
12011-06-04 Paul Eggert <eggert@cs.ucla.edu> 12011-06-04 Paul Eggert <eggert@cs.ucla.edu>
2 2
3 Check for buffer and string overflow more precisely.
4 * buffer.h (BUF_BYTES_MAX): New macro.
5 * lisp.h (STRING_BYTES_MAX): New macro.
6 * alloc.c (Fmake_string):
7 * character.c (string_escape_byte8):
8 * coding.c (coding_alloc_by_realloc):
9 * doprnt.c (doprnt):
10 * editfns.c (Fformat):
11 * eval.c (verror):
12 Use STRING_BYTES_MAX, not MOST_POSITIVE_FIXNUM,
13 since they may not be the same number.
14 * editfns.c (Finsert_char):
15 * fileio.c (Finsert_file_contents):
16 Likewise for BUF_BYTES_MAX.
17
3 Use ptrdiff_t, not int, for sizes. 18 Use ptrdiff_t, not int, for sizes.
4 * image.c (slurp_file): Switch from int to ptrdiff_t. 19 * image.c (slurp_file): Switch from int to ptrdiff_t.
5 All uses changed. 20 All uses changed.
diff --git a/src/alloc.c b/src/alloc.c
index 0c18fca1755..d20ee1e59e3 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -2205,7 +2205,7 @@ INIT must be an integer that represents a character. */)
2205 int len = CHAR_STRING (c, str); 2205 int len = CHAR_STRING (c, str);
2206 EMACS_INT string_len = XINT (length); 2206 EMACS_INT string_len = XINT (length);
2207 2207
2208 if (string_len > MOST_POSITIVE_FIXNUM / len) 2208 if (string_len > STRING_BYTES_MAX / len)
2209 string_overflow (); 2209 string_overflow ();
2210 nbytes = len * string_len; 2210 nbytes = len * string_len;
2211 val = make_uninit_multibyte_string (string_len, nbytes); 2211 val = make_uninit_multibyte_string (string_len, nbytes);
diff --git a/src/buffer.h b/src/buffer.h
index 8c64a24e804..3c91bdfe570 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -306,6 +306,11 @@ do \
306 } \ 306 } \
307while (0) 307while (0)
308 308
309/* Maximum number of bytes in a buffer.
310 A buffer cannot contain more bytes than a 1-origin fixnum can represent,
311 nor can it be so large that C pointer arithmetic stops working. */
312#define BUF_BYTES_MAX min (MOST_POSITIVE_FIXNUM - 1, min (SIZE_MAX, PTRDIFF_MAX))
313
309/* Return the address of byte position N in current buffer. */ 314/* Return the address of byte position N in current buffer. */
310 315
311#define BYTE_POS_ADDR(n) \ 316#define BYTE_POS_ADDR(n) \
diff --git a/src/character.c b/src/character.c
index 4aa1b75cd8c..cff00f44660 100644
--- a/src/character.c
+++ b/src/character.c
@@ -838,7 +838,7 @@ string_escape_byte8 (Lisp_Object string)
838 if (multibyte) 838 if (multibyte)
839 { 839 {
840 if ((MOST_POSITIVE_FIXNUM - nchars) / 3 < byte8_count 840 if ((MOST_POSITIVE_FIXNUM - nchars) / 3 < byte8_count
841 || (MOST_POSITIVE_FIXNUM - nbytes) / 2 < byte8_count) 841 || (STRING_BYTES_MAX - nbytes) / 2 < byte8_count)
842 string_overflow (); 842 string_overflow ();
843 843
844 /* Convert 2-byte sequence of byte8 chars to 4-byte octal. */ 844 /* Convert 2-byte sequence of byte8 chars to 4-byte octal. */
@@ -847,7 +847,7 @@ string_escape_byte8 (Lisp_Object string)
847 } 847 }
848 else 848 else
849 { 849 {
850 if ((MOST_POSITIVE_FIXNUM - nchars) / 3 < byte8_count) 850 if ((STRING_BYTES_MAX - nchars) / 3 < byte8_count)
851 string_overflow (); 851 string_overflow ();
852 852
853 /* Convert 1-byte sequence of byte8 chars to 4-byte octal. */ 853 /* Convert 1-byte sequence of byte8 chars to 4-byte octal. */
diff --git a/src/coding.c b/src/coding.c
index 6ccaf354c74..64e8e41a5a1 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -1071,8 +1071,8 @@ coding_set_destination (struct coding_system *coding)
1071static void 1071static void
1072coding_alloc_by_realloc (struct coding_system *coding, EMACS_INT bytes) 1072coding_alloc_by_realloc (struct coding_system *coding, EMACS_INT bytes)
1073{ 1073{
1074 if (coding->dst_bytes >= MOST_POSITIVE_FIXNUM - bytes) 1074 if (STRING_BYTES_MAX - coding->dst_bytes < bytes)
1075 error ("Maximum size of buffer or string exceeded"); 1075 string_overflow ();
1076 coding->destination = (unsigned char *) xrealloc (coding->destination, 1076 coding->destination = (unsigned char *) xrealloc (coding->destination,
1077 coding->dst_bytes + bytes); 1077 coding->dst_bytes + bytes);
1078 coding->dst_bytes += bytes; 1078 coding->dst_bytes += bytes;
diff --git a/src/doprnt.c b/src/doprnt.c
index d2abc119912..5ca3ea89be6 100644
--- a/src/doprnt.c
+++ b/src/doprnt.c
@@ -329,7 +329,7 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
329 minlen = atoi (&fmtcpy[1]); 329 minlen = atoi (&fmtcpy[1]);
330 string = va_arg (ap, char *); 330 string = va_arg (ap, char *);
331 tem = strlen (string); 331 tem = strlen (string);
332 if (tem > MOST_POSITIVE_FIXNUM) 332 if (tem > STRING_BYTES_MAX)
333 error ("String for %%s or %%S format is too long"); 333 error ("String for %%s or %%S format is too long");
334 width = strwidth (string, tem); 334 width = strwidth (string, tem);
335 goto doit1; 335 goto doit1;
@@ -338,7 +338,7 @@ doprnt (char *buffer, register size_t bufsize, const char *format,
338 doit: 338 doit:
339 /* Coming here means STRING contains ASCII only. */ 339 /* Coming here means STRING contains ASCII only. */
340 tem = strlen (string); 340 tem = strlen (string);
341 if (tem > MOST_POSITIVE_FIXNUM) 341 if (tem > STRING_BYTES_MAX)
342 error ("Format width or precision too large"); 342 error ("Format width or precision too large");
343 width = tem; 343 width = tem;
344 doit1: 344 doit1:
diff --git a/src/editfns.c b/src/editfns.c
index b18a35fe295..b7951c45fac 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -2341,7 +2341,7 @@ from adjoining text, if those properties are sticky. */)
2341 len = CHAR_STRING (XFASTINT (character), str); 2341 len = CHAR_STRING (XFASTINT (character), str);
2342 else 2342 else
2343 str[0] = XFASTINT (character), len = 1; 2343 str[0] = XFASTINT (character), len = 1;
2344 if (MOST_POSITIVE_FIXNUM / len < XINT (count)) 2344 if (BUF_BYTES_MAX / len < XINT (count))
2345 error ("Maximum buffer size would be exceeded"); 2345 error ("Maximum buffer size would be exceeded");
2346 n = XINT (count) * len; 2346 n = XINT (count) * len;
2347 if (n <= 0) 2347 if (n <= 0)
@@ -3588,7 +3588,7 @@ usage: (format STRING &rest OBJECTS) */)
3588 char initial_buffer[4000]; 3588 char initial_buffer[4000];
3589 char *buf = initial_buffer; 3589 char *buf = initial_buffer;
3590 EMACS_INT bufsize = sizeof initial_buffer; 3590 EMACS_INT bufsize = sizeof initial_buffer;
3591 EMACS_INT max_bufsize = min (MOST_POSITIVE_FIXNUM + 1, SIZE_MAX); 3591 EMACS_INT max_bufsize = STRING_BYTES_MAX + 1;
3592 char *p; 3592 char *p;
3593 Lisp_Object buf_save_value IF_LINT (= {0}); 3593 Lisp_Object buf_save_value IF_LINT (= {0});
3594 register char *format, *end, *format_start; 3594 register char *format, *end, *format_start;
diff --git a/src/eval.c b/src/eval.c
index f8bc0a9f6aa..ef5abac17ae 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1994,7 +1994,7 @@ verror (const char *m, va_list ap)
1994{ 1994{
1995 char buf[4000]; 1995 char buf[4000];
1996 size_t size = sizeof buf; 1996 size_t size = sizeof buf;
1997 size_t size_max = min (MOST_POSITIVE_FIXNUM + 1, SIZE_MAX); 1997 size_t size_max = STRING_BYTES_MAX + 1;
1998 size_t mlen = strlen (m); 1998 size_t mlen = strlen (m);
1999 char *buffer = buf; 1999 char *buffer = buf;
2000 size_t used; 2000 size_t used;
diff --git a/src/fileio.c b/src/fileio.c
index 2f7716d5b54..d9bc28d8c37 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -3248,7 +3248,7 @@ variable `last-coding-system-used' to the coding system actually used. */)
3248 /* Check whether the size is too large or negative, which can happen on a 3248 /* Check whether the size is too large or negative, which can happen on a
3249 platform that allows file sizes greater than the maximum off_t value. */ 3249 platform that allows file sizes greater than the maximum off_t value. */
3250 if (! not_regular 3250 if (! not_regular
3251 && ! (0 <= st.st_size && st.st_size <= MOST_POSITIVE_FIXNUM)) 3251 && ! (0 <= st.st_size && st.st_size <= BUF_BYTES_MAX))
3252 error ("Maximum buffer size exceeded"); 3252 error ("Maximum buffer size exceeded");
3253 3253
3254 /* Prevent redisplay optimizations. */ 3254 /* Prevent redisplay optimizations. */
diff --git a/src/lisp.h b/src/lisp.h
index 1defda151ae..ad4614c7b16 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -766,6 +766,12 @@ extern EMACS_INT string_bytes (struct Lisp_String *);
766 766
767#endif /* not GC_CHECK_STRING_BYTES */ 767#endif /* not GC_CHECK_STRING_BYTES */
768 768
769/* A string cannot contain more bytes than a fixnum can represent,
770 nor can it be so long that C pointer arithmetic stops working on
771 the string plus a terminating null. */
772#define STRING_BYTES_MAX \
773 min (MOST_POSITIVE_FIXNUM, min (SIZE_MAX, PTRDIFF_MAX) - 1)
774
769/* Mark STR as a unibyte string. */ 775/* Mark STR as a unibyte string. */
770#define STRING_SET_UNIBYTE(STR) \ 776#define STRING_SET_UNIBYTE(STR) \
771 do { if (EQ (STR, empty_multibyte_string)) \ 777 do { if (EQ (STR, empty_multibyte_string)) \