+2011-06-08 Paul Eggert <eggert@cs.ucla.edu>
+
+ * alloc.c: Catch some string size overflows that we were missing.
+ (XMALLOC_OVERRUN_CHECK_SIZE) [!XMALLOC_OVERRUN_CHECK]: Define to 0,
+ for convenience in STRING_BYTES_MAX.
+ (STRING_BYTES_MAX): New macro, superseding the old one in lisp.h.
+ The definition here is exact; the one in lisp.h was approximate.
+ (allocate_string_data): Check for string overflow. This catches
+ some instances we weren't catching before. Also, it catches
+ size_t overflow on (unusual) hosts where SIZE_MAX <= min
+ (PTRDIFF_MAX, MOST_POSITIVE_FIXNUM), e.g., when size_t is 32 bits
+ and ptrdiff_t and EMACS_INT are both 64 bits.
+ * character.c, coding.c, doprnt.c, editfns.c, eval.c:
+ All uses of STRING_BYTES_MAX replaced by STRING_BYTES_BOUND.
+ * lisp.h (STRING_BYTES_BOUND): Renamed from STRING_BYTES_MAX.
+
2011-06-07 Paul Eggert <eggert@cs.ucla.edu>
* character.c (string_escape_byte8): Fix nbytes/nchars typo.
}
-#ifdef XMALLOC_OVERRUN_CHECK
+#ifndef XMALLOC_OVERRUN_CHECK
+#define XMALLOC_OVERRUN_CHECK_SIZE 0
+#else
/* Check for overrun in malloc'ed buffers by wrapping a 16 byte header
and a 16 byte trailer around each block.
#define GC_STRING_EXTRA (GC_STRING_OVERRUN_COOKIE_SIZE)
+/* Exact bound on the number of bytes in a string, not counting the
+ terminating null. A string cannot contain more bytes than
+ STRING_BYTES_BOUND, nor can it be so long that the size_t
+ arithmetic in allocate_string_data would overflow while it is
+ calculating a value to be passed to malloc. */
+#define STRING_BYTES_MAX \
+ min (STRING_BYTES_BOUND, \
+ ((SIZE_MAX - XMALLOC_OVERRUN_CHECK_SIZE - GC_STRING_EXTRA \
+ - offsetof (struct sblock, first_data) \
+ - SDATA_DATA_OFFSET) \
+ & ~(sizeof (EMACS_INT) - 1)))
+
/* Initialize string allocation. Called from init_alloc_once. */
static void
struct sblock *b;
EMACS_INT needed, old_nbytes;
+ if (STRING_BYTES_MAX < nbytes)
+ string_overflow ();
+
/* Determine the number of bytes needed to store NBYTES bytes
of string data. */
needed = SDATA_SIZE (nbytes);
if (multibyte)
{
if ((MOST_POSITIVE_FIXNUM - nchars) / 3 < byte8_count
- || (STRING_BYTES_MAX - nbytes) / 2 < byte8_count)
+ || (STRING_BYTES_BOUND - nbytes) / 2 < byte8_count)
string_overflow ();
/* Convert 2-byte sequence of byte8 chars to 4-byte octal. */
}
else
{
- if ((STRING_BYTES_MAX - nbytes) / 3 < byte8_count)
+ if ((STRING_BYTES_BOUND - nbytes) / 3 < byte8_count)
string_overflow ();
/* Convert 1-byte sequence of byte8 chars to 4-byte octal. */
static void
coding_alloc_by_realloc (struct coding_system *coding, EMACS_INT bytes)
{
- if (STRING_BYTES_MAX - coding->dst_bytes < bytes)
+ if (STRING_BYTES_BOUND - coding->dst_bytes < bytes)
string_overflow ();
coding->destination = (unsigned char *) xrealloc (coding->destination,
coding->dst_bytes + bytes);
minlen = atoi (&fmtcpy[1]);
string = va_arg (ap, char *);
tem = strlen (string);
- if (tem > STRING_BYTES_MAX)
+ if (STRING_BYTES_BOUND < tem)
error ("String for %%s or %%S format is too long");
width = strwidth (string, tem);
goto doit1;
doit:
/* Coming here means STRING contains ASCII only. */
tem = strlen (string);
- if (tem > STRING_BYTES_MAX)
+ if (STRING_BYTES_BOUND < tem)
error ("Format width or precision too large");
width = tem;
doit1:
char initial_buffer[4000];
char *buf = initial_buffer;
EMACS_INT bufsize = sizeof initial_buffer;
- EMACS_INT max_bufsize = STRING_BYTES_MAX + 1;
+ EMACS_INT max_bufsize = STRING_BYTES_BOUND + 1;
char *p;
Lisp_Object buf_save_value IF_LINT (= {0});
register char *format, *end, *format_start;
{
char buf[4000];
size_t size = sizeof buf;
- size_t size_max = STRING_BYTES_MAX + 1;
+ size_t size_max = STRING_BYTES_BOUND + 1;
size_t mlen = strlen (m);
char *buffer = buf;
size_t used;
#endif /* not GC_CHECK_STRING_BYTES */
-/* A string cannot contain more bytes than a fixnum can represent,
- nor can it be so long that C pointer arithmetic stops working on
- the string plus a terminating null. */
-#define STRING_BYTES_MAX \
- min (MOST_POSITIVE_FIXNUM, min (SIZE_MAX, PTRDIFF_MAX) - 1)
+/* An upper bound on the number of bytes in a Lisp string, not
+ counting the terminating null. This a tight enough bound to
+ prevent integer overflow errors that would otherwise occur during
+ string size calculations. A string cannot contain more bytes than
+ a fixnum can represent, nor can it be so long that C pointer
+ arithmetic stops working on the string plus its terminating null.
+ Although the actual size limit (see STRING_BYTES_MAX in alloc.c)
+ may be a bit smaller than STRING_BYTES_BOUND, calculating it here
+ would expose alloc.c internal details that we'd rather keep
+ private. The cast to ptrdiff_t ensures that STRING_BYTES_BOUND is
+ signed. */
+#define STRING_BYTES_BOUND \
+ min (MOST_POSITIVE_FIXNUM, (ptrdiff_t) min (SIZE_MAX, PTRDIFF_MAX) - 1)
/* Mark STR as a unibyte string. */
#define STRING_SET_UNIBYTE(STR) \