From cb993c584c8ef91f5352ec9aa97d26fd76cfd643 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 29 Sep 2011 20:25:46 -0700 Subject: [PATCH] Port --enable-checking=all to Fedora 14 x86. * alloc.c (XMALLOC_OVERRUN_CHECK_OVERHEAD, XMALLOC_OVERRUN_CHECK_SIZE): Move to lisp.h. (xmalloc_put_size, xmalloc_get_size, overrun_check_malloc) (overrun_check_realloc, overrun_check_free): Use XMALLOC_OVERRUN_SIZE_SIZE, not sizeof (size_t). That way, xmalloc returns a properly-aligned pointer even if XMALLOC_OVERRUN_CHECK is defined. The old debugging code happened to align OK on typical 64-bit hosts, but not on Fedora 14 x86. * charset.c (syms_of_charset): Take XMALLOC_OVERRUN_CHECK_OVERHEAD into account when calculating the initial malloc maximum. * lisp.h (XMALLOC_OVERRUN_CHECK_OVERHEAD, XMALLOC_OVERRUN_CHECK_SIZE): Move here from alloc.c, so that charset.c can use it too. Properly align; the old code wasn't right for common 32-bit hosts when configured with --enable-checking=all. (XMALLOC_BASE_ALIGNMENT, COMMON_MULTIPLE, XMALLOC_HEADER_ALIGNMENT) (XMALLOC_OVERRUN_SIZE_SIZE): New macros. --- src/ChangeLog | 20 ++++++++++++++++++++ src/alloc.c | 47 +++++++++++++++-------------------------------- src/charset.c | 2 +- src/lisp.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index dcbeffac1b4..d6e5390c84f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,23 @@ +2011-09-30 Paul Eggert + + Port --enable-checking=all to Fedora 14 x86. + * alloc.c (XMALLOC_OVERRUN_CHECK_OVERHEAD, XMALLOC_OVERRUN_CHECK_SIZE): + Move to lisp.h. + (xmalloc_put_size, xmalloc_get_size, overrun_check_malloc) + (overrun_check_realloc, overrun_check_free): + Use XMALLOC_OVERRUN_SIZE_SIZE, not sizeof (size_t). + That way, xmalloc returns a properly-aligned pointer even if + XMALLOC_OVERRUN_CHECK is defined. The old debugging code happened + to align OK on typical 64-bit hosts, but not on Fedora 14 x86. + * charset.c (syms_of_charset): Take XMALLOC_OVERRUN_CHECK_OVERHEAD + into account when calculating the initial malloc maximum. + * lisp.h (XMALLOC_OVERRUN_CHECK_OVERHEAD, XMALLOC_OVERRUN_CHECK_SIZE): + Move here from alloc.c, so that charset.c can use it too. + Properly align; the old code wasn't right for common 32-bit hosts + when configured with --enable-checking=all. + (XMALLOC_BASE_ALIGNMENT, COMMON_MULTIPLE, XMALLOC_HEADER_ALIGNMENT) + (XMALLOC_OVERRUN_SIZE_SIZE): New macros. + 2011-09-29 Eli Zaretskii * sysdep.c (snprintf) [EOVERFLOW]: If EOVERFLOW is not defined, diff --git a/src/alloc.c b/src/alloc.c index ad1741e308f..4c5094b8f48 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -482,27 +482,10 @@ buffer_memory_full (EMACS_INT nbytes) xsignal (Qnil, Vmemory_signal_data); } - -#ifndef XMALLOC_OVERRUN_CHECK -#define XMALLOC_OVERRUN_CHECK_OVERHEAD 0 -#else +#ifdef XMALLOC_OVERRUN_CHECK /* Check for overrun in malloc'ed buffers by wrapping a header and trailer - around each block. - - The header consists of 16 fixed bytes followed by sizeof (size_t) bytes - containing the original block size in little-endian order, - while the trailer consists of 16 fixed bytes. - - The header is used to detect whether this block has been allocated - through these functions -- as it seems that some low-level libc - functions may bypass the malloc hooks. -*/ - - -#define XMALLOC_OVERRUN_CHECK_SIZE 16 -#define XMALLOC_OVERRUN_CHECK_OVERHEAD \ - (2 * XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t)) + around each block. */ static char const xmalloc_overrun_check_header[XMALLOC_OVERRUN_CHECK_SIZE] = { '\x9a', '\x9b', '\xae', '\xaf', @@ -522,9 +505,9 @@ static void xmalloc_put_size (unsigned char *ptr, size_t size) { int i; - for (i = 0; i < sizeof (size_t); i++) + for (i = 0; i < XMALLOC_OVERRUN_SIZE_SIZE; i++) { - *--ptr = size & (1 << CHAR_BIT) - 1; + *--ptr = size & ((1 << CHAR_BIT) - 1); size >>= CHAR_BIT; } } @@ -534,8 +517,8 @@ xmalloc_get_size (unsigned char *ptr) { size_t size = 0; int i; - ptr -= sizeof (size_t); - for (i = 0; i < sizeof (size_t); i++) + ptr -= XMALLOC_OVERRUN_SIZE_SIZE; + for (i = 0; i < XMALLOC_OVERRUN_SIZE_SIZE; i++) { size <<= CHAR_BIT; size += *ptr++; @@ -579,7 +562,7 @@ overrun_check_malloc (size_t size) if (val && check_depth == 1) { memcpy (val, xmalloc_overrun_check_header, XMALLOC_OVERRUN_CHECK_SIZE); - val += XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t); + val += XMALLOC_OVERRUN_CHECK_SIZE + XMALLOC_OVERRUN_SIZE_SIZE; xmalloc_put_size (val, size); memcpy (val + size, xmalloc_overrun_check_trailer, XMALLOC_OVERRUN_CHECK_SIZE); @@ -603,7 +586,7 @@ overrun_check_realloc (POINTER_TYPE *block, size_t size) if (val && check_depth == 1 && memcmp (xmalloc_overrun_check_header, - val - XMALLOC_OVERRUN_CHECK_SIZE - sizeof (size_t), + val - XMALLOC_OVERRUN_CHECK_SIZE - XMALLOC_OVERRUN_SIZE_SIZE, XMALLOC_OVERRUN_CHECK_SIZE) == 0) { size_t osize = xmalloc_get_size (val); @@ -611,8 +594,8 @@ overrun_check_realloc (POINTER_TYPE *block, size_t size) XMALLOC_OVERRUN_CHECK_SIZE)) abort (); memset (val + osize, 0, XMALLOC_OVERRUN_CHECK_SIZE); - val -= XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t); - memset (val, 0, XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t)); + val -= XMALLOC_OVERRUN_CHECK_SIZE + XMALLOC_OVERRUN_SIZE_SIZE; + memset (val, 0, XMALLOC_OVERRUN_CHECK_SIZE + XMALLOC_OVERRUN_SIZE_SIZE); } val = (unsigned char *) realloc ((POINTER_TYPE *)val, size + overhead); @@ -620,7 +603,7 @@ overrun_check_realloc (POINTER_TYPE *block, size_t size) if (val && check_depth == 1) { memcpy (val, xmalloc_overrun_check_header, XMALLOC_OVERRUN_CHECK_SIZE); - val += XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t); + val += XMALLOC_OVERRUN_CHECK_SIZE + XMALLOC_OVERRUN_SIZE_SIZE; xmalloc_put_size (val, size); memcpy (val + size, xmalloc_overrun_check_trailer, XMALLOC_OVERRUN_CHECK_SIZE); @@ -640,7 +623,7 @@ overrun_check_free (POINTER_TYPE *block) if (val && check_depth == 1 && memcmp (xmalloc_overrun_check_header, - val - XMALLOC_OVERRUN_CHECK_SIZE - sizeof (size_t), + val - XMALLOC_OVERRUN_CHECK_SIZE - XMALLOC_OVERRUN_SIZE_SIZE, XMALLOC_OVERRUN_CHECK_SIZE) == 0) { size_t osize = xmalloc_get_size (val); @@ -648,12 +631,12 @@ overrun_check_free (POINTER_TYPE *block) XMALLOC_OVERRUN_CHECK_SIZE)) abort (); #ifdef XMALLOC_CLEAR_FREE_MEMORY - val -= XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t); + val -= XMALLOC_OVERRUN_CHECK_SIZE + XMALLOC_OVERRUN_SIZE_SIZE; memset (val, 0xff, osize + XMALLOC_OVERRUN_CHECK_OVERHEAD); #else memset (val + osize, 0, XMALLOC_OVERRUN_CHECK_SIZE); - val -= XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t); - memset (val, 0, XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t)); + val -= XMALLOC_OVERRUN_CHECK_SIZE + XMALLOC_OVERRUN_SIZE_SIZE; + memset (val, 0, XMALLOC_OVERRUN_CHECK_SIZE + XMALLOC_OVERRUN_SIZE_SIZE); #endif } diff --git a/src/charset.c b/src/charset.c index 6967b9df611..1209ac6b68d 100644 --- a/src/charset.c +++ b/src/charset.c @@ -2337,7 +2337,7 @@ syms_of_charset (void) mmap for larger allocations, and these don't work well across dumped systems. */ enum { - initial_malloc_max = (1 << 16) - 1, + initial_malloc_max = (1 << 16) - 1 - XMALLOC_OVERRUN_CHECK_OVERHEAD, charset_table_size_init = initial_malloc_max / sizeof (struct charset) }; diff --git a/src/lisp.h b/src/lisp.h index e9a525a32b5..7aba299f162 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3568,6 +3568,54 @@ extern int initialized; extern int immediate_quit; /* Nonzero means ^G can quit instantly */ +/* Overhead for overrun check in malloc'ed buffers. The check + operates by wrapping a header and trailer around each block. + + The header consists of XMALLOC_OVERRUN_CHECK_SIZE fixed bytes + followed by XMALLOC_OVERRUN_SIZE_SIZE bytes containing the original + block size in little-endian order. The trailer consists of + XMALLOC_OVERRUN_CHECK_SIZE fixed bytes. + + The header is used to detect whether this block has been allocated + through these functions, as some low-level libc functions may + bypass the malloc hooks. */ + +#ifndef XMALLOC_OVERRUN_CHECK +# define XMALLOC_OVERRUN_CHECK_OVERHEAD 0 +#else + +# define XMALLOC_OVERRUN_CHECK_SIZE 16 +# define XMALLOC_OVERRUN_CHECK_OVERHEAD \ + (2 * XMALLOC_OVERRUN_CHECK_SIZE + XMALLOC_OVERRUN_SIZE_SIZE) + +/* Define XMALLOC_OVERRUN_SIZE_SIZE so that (1) it's large enough to + hold a size_t value and (2) the header size is a multiple of the + alignment that Emacs needs for C types and for USE_LSB_TAG. */ +# define XMALLOC_BASE_ALIGNMENT \ + offsetof ( \ + struct { \ + union { long double d; intmax_t i; void *p; } u; \ + char c; \ + }, \ + c) +# ifdef USE_LSB_TAG +/* A common multiple of the positive integers A and B. Ideally this + would be the least common multiple, but there's no way to do that + as a constant expression in C, so do the best that we can easily do. */ +# define COMMON_MULTIPLE(a, b) \ + ((a) % (b) == 0 ? (a) : (b) % (a) == 0 ? (b) : (a) * (b)) +# define XMALLOC_HEADER_ALIGNMENT \ + COMMON_MULTIPLE (1 << GCTYPEBITS, XMALLOC_BASE_ALIGNMENT) +# else +# define XMALLOC_HEADER_ALIGNMENT XMALLOC_BASE_ALIGNMENT +# endif +# define XMALLOC_OVERRUN_SIZE_SIZE \ + (((XMALLOC_OVERRUN_CHECK_SIZE + sizeof (size_t) \ + + XMALLOC_HEADER_ALIGNMENT - 1) \ + / XMALLOC_HEADER_ALIGNMENT * XMALLOC_HEADER_ALIGNMENT) \ + - XMALLOC_OVERRUN_CHECK_SIZE) +#endif + extern POINTER_TYPE *xmalloc (size_t); extern POINTER_TYPE *xrealloc (POINTER_TYPE *, size_t); extern void xfree (POINTER_TYPE *); -- 2.39.2