aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKim F. Storm <[email protected]>2004-11-30 00:30:56 +0000
committerKim F. Storm <[email protected]>2004-11-30 00:30:56 +0000
commit212f33f185f9d93562aec9ab01625557c8003ee0 (patch)
tree6f446fb9b00a1171f88800cc63f97bf5f3b18e53 /src
parentfc36888973845984731c651411f43b039ec39be3 (diff)
Add more checks for buffer overruns.
(XMALLOC_OVERRUN_CHECK_SIZE, xmalloc_overrun_check_header) xmalloc_overrun_check_trailer, overrun_check_malloc) overrun_check_realloc, overrun_check_free): Add. (GC_STRING_EXTRA, string_overrun_pattern): Add. (check_sblock, allocate_string_data, compact_small_strings): Set and check string_overrun_pattern if GC_CHECK_STRING_OVERRUN. (check_cons_list): Condition on GC_CHECK_CONS_LIST. (check_string_free_list): Add. (allocate_string, sweep_strings): Call check_string_free_list.
Diffstat (limited to 'src')
-rw-r--r--src/alloc.c161
1 files changed, 152 insertions, 9 deletions
diff --git a/src/alloc.c b/src/alloc.c
index be2a4fa1bb..223a49ee56 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -518,6 +518,101 @@ buffer_memory_full ()
/* Like malloc but check for no memory and block interrupt input.. */
+#ifdef XMALLOC_OVERRUN_CHECK
+
+#define XMALLOC_OVERRUN_CHECK_SIZE 16
+static char xmalloc_overrun_check_header[XMALLOC_OVERRUN_CHECK_SIZE-4] =
+ { 0x9a, 0x9b, 0xae, 0xaf,
+ 0xbf, 0xbe, 0xce, 0xcf,
+ 0xea, 0xeb, 0xec, 0xed };
+
+static char xmalloc_overrun_check_trailer[XMALLOC_OVERRUN_CHECK_SIZE] =
+ { 0xaa, 0xab, 0xac, 0xad,
+ 0xba, 0xbb, 0xbc, 0xbd,
+ 0xca, 0xcb, 0xcc, 0xcd,
+ 0xda, 0xdb, 0xdc, 0xdd };
+
+POINTER_TYPE *
+overrun_check_malloc (size)
+ size_t size;
+{
+ register char *val;
+
+ val = (char *) malloc (size + XMALLOC_OVERRUN_CHECK_SIZE*2);
+ if (val)
+ {
+ bcopy (xmalloc_overrun_check_header, val, XMALLOC_OVERRUN_CHECK_SIZE - 4);
+ bcopy (&size, val + XMALLOC_OVERRUN_CHECK_SIZE - 4, sizeof (size));
+ val += XMALLOC_OVERRUN_CHECK_SIZE;
+ bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE);
+ }
+ return (POINTER_TYPE *)val;
+}
+
+POINTER_TYPE *
+overrun_check_realloc (block, size)
+ POINTER_TYPE *block;
+ size_t size;
+{
+ register char *val = (char *)block;
+
+ if (val
+ && bcmp (xmalloc_overrun_check_header,
+ val - XMALLOC_OVERRUN_CHECK_SIZE,
+ XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0)
+ {
+ size_t osize;
+ bcopy (val - 4, &osize, sizeof (osize));
+ if (bcmp (xmalloc_overrun_check_trailer,
+ val + osize,
+ XMALLOC_OVERRUN_CHECK_SIZE))
+ abort ();
+ val -= XMALLOC_OVERRUN_CHECK_SIZE;
+ }
+
+ val = (char *) realloc ((POINTER_TYPE *)val, size + XMALLOC_OVERRUN_CHECK_SIZE*2);
+
+ if (val)
+ {
+ bcopy (xmalloc_overrun_check_header, val, XMALLOC_OVERRUN_CHECK_SIZE - 4);
+ bcopy (&size, val + XMALLOC_OVERRUN_CHECK_SIZE - 4, sizeof (size));
+ val += XMALLOC_OVERRUN_CHECK_SIZE;
+ bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE);
+ }
+ return (POINTER_TYPE *)val;
+}
+
+void
+overrun_check_free (block)
+ POINTER_TYPE *block;
+{
+ char *val = (char *)block;
+
+ if (val
+ && bcmp (xmalloc_overrun_check_header,
+ val - XMALLOC_OVERRUN_CHECK_SIZE,
+ XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0)
+ {
+ size_t osize;
+ bcopy (val - 4, &osize, sizeof (osize));
+ if (bcmp (xmalloc_overrun_check_trailer,
+ val + osize,
+ XMALLOC_OVERRUN_CHECK_SIZE))
+ abort ();
+ val -= XMALLOC_OVERRUN_CHECK_SIZE;
+ }
+
+ free (val);
+}
+
+#undef malloc
+#undef realloc
+#undef free
+#define malloc overrun_check_malloc
+#define realloc overrun_check_realloc
+#define free overrun_check_free
+#endif
+
POINTER_TYPE *
xmalloc (size)
size_t size;
@@ -602,7 +697,9 @@ safe_alloca_unwind (arg)
number of bytes to allocate, TYPE describes the intended use of the
allcated memory block (for strings, for conses, ...). */
+#ifndef USE_LSB_TAG
static void *lisp_malloc_loser;
+#endif
static POINTER_TYPE *
lisp_malloc (nbytes, type)
@@ -1428,6 +1525,14 @@ static int total_string_size;
#endif /* not GC_CHECK_STRING_BYTES */
+
+#ifdef GC_CHECK_STRING_OVERRUN
+#define GC_STRING_EXTRA 4
+static char string_overrun_pattern[GC_STRING_EXTRA] = { 0xde, 0xad, 0xbe, 0xef };
+#else
+#define GC_STRING_EXTRA 0
+#endif
+
/* Value is the size of an sdata structure large enough to hold NBYTES
bytes of string data. The value returned includes a terminating
NUL byte, the size of the sdata structure, and padding. */
@@ -1515,7 +1620,7 @@ check_sblock (b)
nbytes = SDATA_NBYTES (from);
nbytes = SDATA_SIZE (nbytes);
- from_end = (struct sdata *) ((char *) from + nbytes);
+ from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA);
}
}
@@ -1548,6 +1653,25 @@ check_string_bytes (all_p)
#endif /* GC_CHECK_STRING_BYTES */
+#ifdef GC_CHECK_STRING_FREE_LIST
+
+static void
+check_string_free_list ()
+{
+ struct Lisp_String *s;
+
+ /* Pop a Lisp_String off the free-list. */
+ s = string_free_list;
+ while (s != NULL)
+ {
+ if ((unsigned)s < 1024)
+ abort();
+ s = NEXT_FREE_LISP_STRING (s);
+ }
+}
+#else
+#define check_string_free_list()
+#endif
/* Return a new Lisp_String. */
@@ -1579,6 +1703,8 @@ allocate_string ()
total_free_strings += STRING_BLOCK_SIZE;
}
+ check_string_free_list();
+
/* Pop a Lisp_String off the free-list. */
s = string_free_list;
string_free_list = NEXT_FREE_LISP_STRING (s);
@@ -1648,7 +1774,7 @@ allocate_string_data (s, nchars, nbytes)
mallopt (M_MMAP_MAX, 0);
#endif
- b = (struct sblock *) lisp_malloc (size, MEM_TYPE_NON_LISP);
+ b = (struct sblock *) lisp_malloc (size + GC_STRING_EXTRA, MEM_TYPE_NON_LISP);
#ifdef DOUG_LEA_MALLOC
/* Back to a reasonable maximum of mmap'ed areas. */
@@ -1663,7 +1789,7 @@ allocate_string_data (s, nchars, nbytes)
else if (current_sblock == NULL
|| (((char *) current_sblock + SBLOCK_SIZE
- (char *) current_sblock->next_free)
- < needed))
+ < (needed + GC_STRING_EXTRA)))
{
/* Not enough room in the current sblock. */
b = (struct sblock *) lisp_malloc (SBLOCK_SIZE, MEM_TYPE_NON_LISP);
@@ -1692,7 +1818,10 @@ allocate_string_data (s, nchars, nbytes)
s->size = nchars;
s->size_byte = nbytes;
s->data[nbytes] = '\0';
- b->next_free = (struct sdata *) ((char *) data + needed);
+#ifdef GC_CHECK_STRING_OVERRUN
+ bcopy(string_overrun_pattern, (char *) data + needed, GC_STRING_EXTRA);
+#endif
+ b->next_free = (struct sdata *) ((char *) data + needed + GC_STRING_EXTRA);
/* If S had already data assigned, mark that as free by setting its
string back-pointer to null, and recording the size of the data
@@ -1797,9 +1926,13 @@ sweep_strings ()
}
}
+ check_string_free_list();
+
string_blocks = live_blocks;
free_large_strings ();
compact_small_strings ();
+
+ check_string_free_list();
}
@@ -1871,28 +2004,38 @@ compact_small_strings ()
else
nbytes = SDATA_NBYTES (from);
+#ifdef GC_CHECK_STRING_BYTES
+ if (nbytes > LARGE_STRING_BYTES)
+ abort ();
+#endif
+
nbytes = SDATA_SIZE (nbytes);
- from_end = (struct sdata *) ((char *) from + nbytes);
+ from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA);
+
+#ifdef GC_CHECK_STRING_OVERRUN
+ if (bcmp(string_overrun_pattern, ((char *) from_end) - GC_STRING_EXTRA, GC_STRING_EXTRA))
+ abort ();
+#endif
/* FROM->string non-null means it's alive. Copy its data. */
if (from->string)
{
/* If TB is full, proceed with the next sblock. */
- to_end = (struct sdata *) ((char *) to + nbytes);
+ to_end = (struct sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
if (to_end > tb_end)
{
tb->next_free = to;
tb = tb->next;
tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE);
to = &tb->first_data;
- to_end = (struct sdata *) ((char *) to + nbytes);
+ to_end = (struct sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
}
/* Copy, and update the string's `data' pointer. */
if (from != to)
{
xassert (tb != b || to <= from);
- safe_bcopy ((char *) from, (char *) to, nbytes);
+ safe_bcopy ((char *) from, (char *) to, nbytes + GC_STRING_EXTRA);
to->string->data = SDATA_DATA (to);
}
@@ -2402,9 +2545,9 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
void
check_cons_list ()
{
+#ifdef GC_CHECK_CONS_LIST
struct Lisp_Cons *tail = cons_free_list;
-#if 0
while (tail)
tail = *(struct Lisp_Cons **)&tail->cdr;
#endif