+#ifdef XMALLOC_OVERRUN_CHECK
+
+/* Check for overrun in malloc'ed buffers by wrapping a 16 byte header
+ and a 16 byte trailer around each block.
+
+ The header consists of 12 fixed bytes + a 4 byte integer contaning the
+ original block size, 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
+
+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 };
+
+/* Macros to insert and extract the block size in the header. */
+
+#define XMALLOC_PUT_SIZE(ptr, size) \
+ (ptr[-1] = (size & 0xff), \
+ ptr[-2] = ((size >> 8) & 0xff), \
+ ptr[-3] = ((size >> 16) & 0xff), \
+ ptr[-4] = ((size >> 24) & 0xff))
+
+#define XMALLOC_GET_SIZE(ptr) \
+ (size_t)((unsigned)(ptr[-1]) | \
+ ((unsigned)(ptr[-2]) << 8) | \
+ ((unsigned)(ptr[-3]) << 16) | \
+ ((unsigned)(ptr[-4]) << 24))
+
+
+/* The call depth in overrun_check functions. For example, this might happen:
+ xmalloc()
+ overrun_check_malloc()
+ -> malloc -> (via hook)_-> emacs_blocked_malloc
+ -> overrun_check_malloc
+ call malloc (hooks are NULL, so real malloc is called).
+ malloc returns 10000.
+ add overhead, return 10016.
+ <- (back in overrun_check_malloc)
+ add overhead again, return 10032
+ xmalloc returns 10032.
+
+ (time passes).
+
+ xfree(10032)
+ overrun_check_free(10032)
+ decrease overhed
+ free(10016) <- crash, because 10000 is the original pointer. */
+
+static int check_depth;
+
+/* Like malloc, but wraps allocated block with header and trailer. */
+
+POINTER_TYPE *
+overrun_check_malloc (size)
+ size_t size;
+{
+ register unsigned char *val;
+ size_t overhead = ++check_depth == 1 ? XMALLOC_OVERRUN_CHECK_SIZE*2 : 0;
+
+ val = (unsigned char *) malloc (size + overhead);
+ if (val && check_depth == 1)
+ {
+ bcopy (xmalloc_overrun_check_header, val, XMALLOC_OVERRUN_CHECK_SIZE - 4);
+ val += XMALLOC_OVERRUN_CHECK_SIZE;
+ XMALLOC_PUT_SIZE(val, size);
+ bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE);
+ }
+ --check_depth;
+ return (POINTER_TYPE *)val;
+}
+
+
+/* Like realloc, but checks old block for overrun, and wraps new block
+ with header and trailer. */
+
+POINTER_TYPE *
+overrun_check_realloc (block, size)
+ POINTER_TYPE *block;
+ size_t size;
+{
+ register unsigned char *val = (unsigned char *)block;
+ size_t overhead = ++check_depth == 1 ? XMALLOC_OVERRUN_CHECK_SIZE*2 : 0;
+
+ if (val
+ && check_depth == 1
+ && bcmp (xmalloc_overrun_check_header,
+ val - XMALLOC_OVERRUN_CHECK_SIZE,
+ XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0)
+ {
+ size_t osize = XMALLOC_GET_SIZE (val);
+ if (bcmp (xmalloc_overrun_check_trailer,
+ val + osize,
+ XMALLOC_OVERRUN_CHECK_SIZE))
+ abort ();
+ bzero (val + osize, XMALLOC_OVERRUN_CHECK_SIZE);
+ val -= XMALLOC_OVERRUN_CHECK_SIZE;
+ bzero (val, XMALLOC_OVERRUN_CHECK_SIZE);
+ }
+
+ val = (unsigned char *) realloc ((POINTER_TYPE *)val, size + overhead);
+
+ if (val && check_depth == 1)
+ {
+ bcopy (xmalloc_overrun_check_header, val, XMALLOC_OVERRUN_CHECK_SIZE - 4);
+ val += XMALLOC_OVERRUN_CHECK_SIZE;
+ XMALLOC_PUT_SIZE(val, size);
+ bcopy (xmalloc_overrun_check_trailer, val + size, XMALLOC_OVERRUN_CHECK_SIZE);
+ }
+ --check_depth;
+ return (POINTER_TYPE *)val;
+}
+
+/* Like free, but checks block for overrun. */
+
+void
+overrun_check_free (block)
+ POINTER_TYPE *block;
+{
+ unsigned char *val = (unsigned char *)block;
+
+ ++check_depth;
+ if (val
+ && check_depth == 1
+ && bcmp (xmalloc_overrun_check_header,
+ val - XMALLOC_OVERRUN_CHECK_SIZE,
+ XMALLOC_OVERRUN_CHECK_SIZE - 4) == 0)
+ {
+ size_t osize = XMALLOC_GET_SIZE (val);
+ if (bcmp (xmalloc_overrun_check_trailer,
+ val + osize,
+ XMALLOC_OVERRUN_CHECK_SIZE))
+ abort ();
+#ifdef XMALLOC_CLEAR_FREE_MEMORY
+ val -= XMALLOC_OVERRUN_CHECK_SIZE;
+ memset (val, 0xff, osize + XMALLOC_OVERRUN_CHECK_SIZE*2);
+#else
+ bzero (val + osize, XMALLOC_OVERRUN_CHECK_SIZE);
+ val -= XMALLOC_OVERRUN_CHECK_SIZE;
+ bzero (val, XMALLOC_OVERRUN_CHECK_SIZE);
+#endif
+ }
+
+ free (val);
+ --check_depth;
+}
+
+#undef malloc
+#undef realloc
+#undef free
+#define malloc overrun_check_malloc
+#define realloc overrun_check_realloc
+#define free overrun_check_free
+#endif
+
+