* src/mm/memory.c: Added ENABLE_MEMCHECK code:
authoredwin <none@none>
Sat, 4 Nov 2006 22:01:51 +0000 (22:01 +0000)
committeredwin <none@none>
Sat, 4 Nov 2006 22:01:51 +0000 (22:01 +0000)
(mem_alloc): Prepared for poisoning memory.
(mem_realloc): Invalidate freed memory.
(mem_free): Invalidate freed memory.
(dump_check_canaries): New function.
(dump_alloc): Added canaries, record allocation.
(dump_realloc): Invalidate freed memory.
(dump_release): Check canaries, invalidate freed memory.

* src/mm/memory.h (dump_allocation_t): New struct.
(dumpinfo_t): Added allocation list for ENABLE_MEMCHECK.

* configure.ac (--enable-memcheck): Added configure flag.

configure.ac
src/mm/memory.c
src/mm/memory.h

index 17c72398d38079706dc6c7cf4a3669f1834d82fb..7c1a7c223b37e8335bbf2a875b91bddcb1eac5e9 100644 (file)
@@ -369,6 +369,23 @@ fi
 AM_CONDITIONAL([NDEBUG], test x"${NDEBUG}" = "xyes")
 
 
+dnl check for memcheck support
+AC_MSG_CHECKING(whether debugging memory checks should be enabled)
+AC_ARG_ENABLE([memcheck],
+              [AS_HELP_STRING(--enable-memcheck,enable debugging memory checks [[default=no]])],
+              [case "${enableval}" in
+                   yes) ENABLE_MEMCHECK=yes;;
+                   *) ENABLE_MEMCHECK=no;;
+               esac],
+              [ENABLE_MEMCHECK=no])
+AC_MSG_RESULT(${ENABLE_MEMCHECK})
+AM_CONDITIONAL([ENABLE_MEMCHECK], test x"${ENABLE_MEMCHECK}" = "xyes")
+
+if test x"${ENABLE_MEMCHECK}" = "xyes"; then
+    AC_DEFINE([ENABLE_MEMCHECK], 1, [perform debugging memory checks])
+fi
+
+
 dnl check for disassembler support
 AC_MSG_CHECKING(whether disassembler should be enabled)
 AC_ARG_ENABLE([disassembler],
index c268a8ffd7432c3cbe2501b312db5662e1f19e2c..ba88a9267b0b2b6cf01fd9beba1b35b96eaac2c1 100644 (file)
@@ -29,7 +29,7 @@
    Changes: Christian Thalinger
                        Edwin Steiner
 
-   $Id: memory.c 5868 2006-10-30 11:21:36Z edwin $
+   $Id: memory.c 5901 2006-11-04 22:01:51Z edwin $
 
 */
 
 #include "vm/vm.h"
 
 
+/* constants for ENABLE_MEMCHECK **********************************************/
+
+#if defined(ENABLE_MEMCHECK)
+#define MEMORY_CANARY_SIZE          16
+#define MEMORY_CANARY_FIRST_BYTE    0xca
+#define MEMORY_CLEAR_BYTE           0xa5
+#endif /* defined(ENABLE_MEMCHECK) */
+
+
 /*******************************************************************************
 
   This structure is used for dump memory allocation if cacao
@@ -254,6 +263,8 @@ void memory_cfree(void *p, s4 size)
 
 void *mem_alloc(s4 size)
 {
+       void *m;
+
        if (size == 0)
                return NULL;
 
@@ -266,7 +277,15 @@ void *mem_alloc(s4 size)
        }
 #endif
 
-       return memory_checked_alloc(size);
+       m = memory_checked_alloc(size);
+
+#if defined(ENABLE_MEMCHECK)
+       /* XXX we would like to poison the memory, but callers rely on */
+       /* the zeroing. This should change sooner or later.            */
+       /* memset(m, MEMORY_CLEAR_BYTE, size); */
+#endif
+
+       return m;
 }
 
 
@@ -286,11 +305,21 @@ void *mem_realloc(void *src, s4 len1, s4 len2)
                memoryusage = (memoryusage - len1) + len2;
 #endif
 
+#if defined(ENABLE_MEMCHECK)
+       if (len2 < len1)
+               memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
+#endif
+
        dst = realloc(src, len2);
 
        if (dst == NULL)
                exceptions_throw_outofmemory_exit();
 
+#if defined(ENABLE_MEMCHECK)
+       if (len2 > len1)
+               memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1);
+#endif
+
        return dst;
 }
 
@@ -310,10 +339,73 @@ void mem_free(void *m, s4 size)
                memoryusage -= size;
 #endif
 
+#if defined(ENABLE_MEMCHECK)
+       /* destroy the contents */
+       memset(m, MEMORY_CLEAR_BYTE, size);
+#endif
+
        free(m);
 }
 
 
+/* dump_check_canaries *********************************************************
+
+   Check canaries in dump memory.
+
+   IN:
+      di...........dumpinfo_t * of the dump area to check
+         bottomsize...dump size down to which the dump area should be checked
+                      (specify 0 to check the whole dump area)
+
+   ERROR HANDLING:
+      If any canary has been changed, this function aborts the VM with
+         an error message.
+
+*******************************************************************************/
+
+#if defined(ENABLE_MEMCHECK)
+void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
+{
+       dump_allocation_t *da;
+       u1 *pm;
+       s4 i, j;
+
+       /* iterate over all dump memory allocations above bottomsize */
+
+       da = di->allocations;
+       while (da && da->useddumpsize >= bottomsize) {
+               /* check canaries */
+
+               pm = da->mem - MEMORY_CANARY_SIZE;
+               for (i=0; i<MEMORY_CANARY_SIZE; ++i)
+                       if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
+                               fprintf(stderr, "canary bytes:");
+                               for (j=0; j<MEMORY_CANARY_SIZE; ++j)
+                                       fprintf(stderr, " %02x", pm[j]);
+                               fprintf(stderr,"\n");
+                               vm_abort("error: dump memory bottom canary killed: "
+                                                "%p (%d bytes allocated at %p)\n",
+                                               pm + i, da->size, da->mem);
+                       }
+
+               pm = da->mem + da->size;
+               for (i=0; i<MEMORY_CANARY_SIZE; ++i)
+                       if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
+                               fprintf(stderr, "canary bytes:");
+                               for (j=0; j<MEMORY_CANARY_SIZE; ++j)
+                                       fprintf(stderr, " %02x", pm[j]);
+                               fprintf(stderr,"\n");
+                               vm_abort("error: dump memory top canary killed: "
+                                                "%p (%d bytes allocated at %p)\n",
+                                               pm + i, da->size, da->mem);
+                       }
+
+               da = da->next;
+       }
+}
+#endif /* defined(ENABLE_MEMCHECK) */
+
+
 /* dump_alloc ******************************************************************
 
    Allocate memory in the dump area.
@@ -355,6 +447,9 @@ void *dump_alloc(s4 size)
 
        void       *m;
        dumpinfo_t *di;
+#if defined(ENABLE_MEMCHECK)
+       s4          origsize = size; /* needed for the canary system */
+#endif
 
        /* If no threads are used, the dumpinfo structure is a static structure   */
        /* defined at the top of this file.                                       */
@@ -364,6 +459,10 @@ void *dump_alloc(s4 size)
        if (size == 0)
                return NULL;
 
+#if defined(ENABLE_MEMCHECK)
+       size += 2*MEMORY_CANARY_SIZE;
+#endif
+
        size = MEMORY_ALIGN(size, ALIGNSIZE);
 
        if (di->useddumpsize + size > di->allocateddumpsize) {
@@ -415,6 +514,40 @@ void *dump_alloc(s4 size)
        m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
                (di->allocateddumpsize - di->useddumpsize);
 
+#if defined(ENABLE_MEMCHECK)
+       {
+               dump_allocation_t *da = NEW(dump_allocation_t);
+               s4 i;
+               u1 *pm;
+
+               /* add the allocation to our linked list of allocations */
+
+               da->next = di->allocations;
+               da->mem = (u1*) m + MEMORY_CANARY_SIZE;
+               da->size = origsize;
+               da->useddumpsize = di->useddumpsize;
+
+               di->allocations = da;
+
+               /* write the canaries */
+
+               pm = (u1*)m;
+               for (i=0; i<MEMORY_CANARY_SIZE; ++i)
+                       pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
+               pm = da->mem + da->size;
+               for (i=0; i<MEMORY_CANARY_SIZE; ++i)
+                       pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
+
+               /* make m point after the bottom canary */
+
+               m = (u1*)m + MEMORY_CANARY_SIZE;
+
+               /* clear the memory */
+
+               memset(m, MEMORY_CLEAR_BYTE, da->size);
+       }
+#endif /* defined(ENABLE_MEMCHECK) */
+
        /* increase used dump size by the allocated memory size */
 
        di->useddumpsize += size;
@@ -448,6 +581,11 @@ void *dump_realloc(void *src, s4 len1, s4 len2)
 
        memcpy(dst, src, len1);
 
+#if defined(ENABLE_MEMCHECK)
+       /* destroy the source */
+       memset(src, MEMORY_CLEAR_BYTE, len1);
+#endif
+
        return dst;
 #endif
 }
@@ -490,6 +628,32 @@ void dump_release(s4 size)
        if ((size < 0) || (size > di->useddumpsize))
                vm_abort("Illegal dump release size: %d", size);
 
+#if defined(ENABLE_MEMCHECK)
+       {
+               dump_allocation_t *da, *next;
+
+               /* check canaries */
+
+               dump_check_canaries(di, size);
+
+               /* iterate over all dump memory allocations about to be released */
+
+               da = di->allocations;
+               while (da && da->useddumpsize >= size) {
+                       next = da->next;
+
+                       /* invalidate the freed memory */
+
+                       memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
+
+                       FREE(da, dump_allocation_t);
+
+                       da = next;
+               }
+               di->allocations = da;
+       }
+#endif /* defined(ENABLE_MEMCHECK) */
+
        /* reset the used dump size to the size specified */
 
        di->useddumpsize = size;
index 0d84bf28722aae64913ead18debe8c6fa67b7728..14b96c8c839f4920a4ce3c13170c2f212318745c 100644 (file)
@@ -28,7 +28,7 @@
 
    Changes: Christian Thalinger
 
-   $Id: memory.h 5900 2006-11-04 17:30:44Z michi $
+   $Id: memory.h 5901 2006-11-04 22:01:51Z edwin $
 
 */
 
@@ -64,12 +64,33 @@ struct dumpblock_t {
 };
 
 
+/* dump_allocation *************************************************************
+
+   This struct is used to record dump memory allocations for ENABLE_MEMCHECK.
+
+*******************************************************************************/
+
+#if defined(ENABLE_MEMCHECK)
+typedef struct dump_allocation_t dump_allocation_t;
+
+struct dump_allocation_t {
+       dump_allocation_t *next;
+       u1                *mem;
+       s4                 useddumpsize;
+       s4                 size;
+};
+#endif
+
+
 /* dumpinfo *******************************************************************/
 
 struct dumpinfo_t {
-       dumpblock_t *currentdumpblock;
-       s4           allocateddumpsize;
-       s4           useddumpsize;
+       dumpblock_t       *currentdumpblock;        /* the current top-most block */
+       s4                 allocateddumpsize;     /* allocated bytes in this area */
+       s4                 useddumpsize;          /* used bytes in this dump area */
+#if defined(ENABLE_MEMCHECK)
+       dump_allocation_t *allocations;       /* list of allocations in this area */
+#endif
 };