Index: /trunk/Ohana/src/libohana/src/ohana_allocate.c
===================================================================
--- /trunk/Ohana/src/libohana/src/ohana_allocate.c	(revision 40116)
+++ /trunk/Ohana/src/libohana/src/ohana_allocate.c	(revision 40117)
@@ -6,7 +6,19 @@
 # include <string.h>
 # include <errno.h>
+# include <malloc.h>
+# include <sys/mman.h>
 
 # define TEST_SAVE_FREE_BLOCKS 0
 # define TEST_SAVE_DROP_BLOCKS 0
+# define USE_MMAP_SIZE 0x80000000
+# define USE_MMAP_LOCAL FALSE
+/* # define USE_MMAP_SIZE 0x100000 - 1M */
+/* USE_MMAP_SIZE is used to tell ohana memory functions to switch to raw mmap/munmap call
+   instead of malloc / realloc / free.  This is in an attempt to avoid a poorly-understood
+   bug in malloc which I've identfied.  The bug is seen in programs running on linux
+   kernel 3.7.6 for glibc 2.8.
+   This did not work as hoped; instead I've had to prevent the use of MMAP all together by 
+   setting M_MMAP_MAX to 0 with mallopt
+*/
 
 # undef OHANA_MEMORY
@@ -49,15 +61,28 @@
 void *ohana_malloc (const char *file, int line, const char *func, size_t Nelem, size_t esize) {
 
+  // we want to call mallopt if we have not yet used the memory system
+  // this disables the use of mmap by malloc and forces it to use on sbrk
+  pthread_mutex_lock(&memBlockListMutex);
+  if (!lastBlock) {
+    mallopt (M_MMAP_MAX, 0);
+  }
+  pthread_mutex_unlock(&memBlockListMutex);
+
   char *ptr;		      // actual user memory allocated
   OhanaMemblock *new;	      // new memblock created to track the user memory
-  size_t size;		      // total number of bytes requested (not items)
-
-  Nelem = MAX (1, Nelem);
-  size = Nelem * esize;
+
+  size_t myNelem = MAX (1, Nelem);
+  size_t size = myNelem * esize; // total number of bytes requested (not items)
+  size_t fullSize = sizeof(OhanaMemblock) + size + 2*sizeof(void *);   // total size is : memblock + data + endpost
   // if (size % 8) size += (8 - size % 8); // do NOT round to 8-byte boundary (did not fix corruption)
 
-  // total size is : memblock + data + endpost
-  new = (OhanaMemblock *) malloc (sizeof(OhanaMemblock) + size + 2*sizeof(void *)); 
-  if (new == NULL) ohana_memabort ("failed to allocate memory (%s, %d, %s)\n", file, line, func);
+  if (USE_MMAP_LOCAL && (fullSize > USE_MMAP_SIZE)) {
+    fprintf (stderr, "** mmap %ld (%s, %d, %s)\n", fullSize, file, line, func);
+    new = (OhanaMemblock *) mmap (NULL, fullSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    if (new == (void *) -1) ohana_memabort ("failed to allocate memory with mmap (%s, %d, %s)\n", file, line, func);
+  } else {
+    new = (OhanaMemblock *) malloc (fullSize); 
+    if (new == NULL) ohana_memabort ("failed to allocate memory (%s, %d, %s)\n", file, line, func);
+  }
   // if (errno == ENOMEM) abort(); I should not check the value of errno if new is not NULL
 
@@ -139,4 +164,8 @@
   size_t oldsize = old->size;
 
+  // total size is : memblock + data + endpost
+  size_t fullSize = sizeof(OhanaMemblock) + size + 2*sizeof(void *);
+  size_t oldFullSize = sizeof(OhanaMemblock) + oldsize + 2*sizeof(void *);
+
   pthread_mutex_lock(&memBlockListMutex);
 
@@ -151,6 +180,12 @@
   // XXX for a test, we are going to always alloc a new block, copy the old data to the new block
   // poison the old block, then free it
-  new = (OhanaMemblock *) malloc (sizeof(OhanaMemblock) + size + 2*sizeof(void *));
-  if (new == NULL) ohana_memabort ("failed to reallocate memory (%s, %d, %s)\n", file, line, func);
+  if (USE_MMAP_LOCAL && (fullSize > USE_MMAP_SIZE)) {
+    fprintf (stderr, "** mmap %ld (%s, %d, %s)\n", fullSize, file, line, func);
+    new = (OhanaMemblock *) mmap (NULL, fullSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    if (new == (void *) -1) ohana_memabort ("failed to allocate memory with mmap (%s, %d, %s)\n", file, line, func);
+  } else {
+    new = (OhanaMemblock *) malloc (fullSize);
+    if (new == NULL) ohana_memabort ("failed to reallocate memory (%s, %d, %s)\n", file, line, func);
+  }
   char *ptr_new = (char *) (new + 1);
   char *ptr_old = (char *) (old + 1);
@@ -165,7 +200,66 @@
 # else
   // ask for new memory
-  // total size is : memblock + data + endpost
-  new = (OhanaMemblock *) realloc (old, sizeof(OhanaMemblock) + size + 2*sizeof(void *));
-  if (new == NULL) ohana_memabort ("failed to reallocate memory (%s, %d, %s)\n", file, line, func);
+
+  if (USE_MMAP_LOCAL && (fullSize > USE_MMAP_SIZE)) {
+    if (oldFullSize > USE_MMAP_SIZE) {
+      // new = (OhanaMemblock *) mremap (old, oldFullSize, fullSize, 0); NOTE: mremap is a Linux / GNU only feature
+      // mmap to mmap (allocate new, copy user bytes, free old)
+      fprintf (stderr, "** mmap 1 %ld to %ld (%s, %d, %s)\n", oldFullSize, fullSize, file, line, func);
+      new = (OhanaMemblock *) mmap (NULL, fullSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      if (new == (void *) -1) ohana_memabort ("failed to allocate memory with mmap (%s, %d, %s)\n", file, line, func);
+      char *ptr_new = (char *) (new + 1);
+      char *ptr_old = (char *) (old + 1);
+      size_t copy_bytes = old->size < size ? old->size : size;
+      memcpy (ptr_new, ptr_old, copy_bytes);
+      memset (ptr_old, 0x7f, old->size);
+      new->nextBlock = old->nextBlock;
+      new->prevBlock = old->prevBlock;
+      new->startblock = OHANA_MEMMAGIC;
+      new->endblock = OHANA_MEMMAGIC;
+      new->freed = FALSE;
+      fprintf (stderr, "** munmap %ld (%s, %d, %s)\n", oldFullSize, file, line, func);
+      int mstatus = munmap (old, oldFullSize); // XXX ???
+      if (mstatus != 0) ohana_memabort ("failed to reallocate memory (%s, %d, %s)\n", file, line, func);
+    } else {
+      // malloc to mmap (allocate new, copy user bytes, free old)
+      fprintf (stderr, "** mmap 2 %ld to %ld (%s, %d, %s)\n", oldFullSize, fullSize, file, line, func);
+      new = (OhanaMemblock *) mmap (NULL, fullSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      if (new == (void *) -1) ohana_memabort ("failed to allocate memory with mmap (%s, %d, %s)\n", file, line, func);
+      char *ptr_new = (char *) (new + 1);
+      char *ptr_old = (char *) (old + 1);
+      size_t copy_bytes = old->size < size ? old->size : size;
+      memcpy (ptr_new, ptr_old, copy_bytes);
+      memset (ptr_old, 0x7f, old->size);
+      new->nextBlock = old->nextBlock;
+      new->prevBlock = old->prevBlock;
+      new->startblock = OHANA_MEMMAGIC;
+      new->endblock = OHANA_MEMMAGIC;
+      new->freed = FALSE;
+      free (old); // XXX ???
+    } 
+  } else { 
+    if (USE_MMAP_LOCAL && (oldFullSize > USE_MMAP_SIZE)) {
+      // mmap to malloc (allocate new, copy user bytes, free old)
+      new = (OhanaMemblock *) malloc (fullSize);
+      if (new == NULL) ohana_memabort ("failed to reallocate memory (%s, %d, %s)\n", file, line, func);
+      char *ptr_new = (char *) (new + 1);
+      char *ptr_old = (char *) (old + 1);
+      size_t copy_bytes = old->size < size ? old->size : size;
+      memcpy (ptr_new, ptr_old, copy_bytes);
+      memset (ptr_old, 0x7f, old->size);
+      new->nextBlock = old->nextBlock;
+      new->prevBlock = old->prevBlock;
+      new->startblock = OHANA_MEMMAGIC;
+      new->endblock = OHANA_MEMMAGIC;
+      new->freed = FALSE;
+      fprintf (stderr, "** munmap %ld (%s, %d, %s)\n", oldFullSize, file, line, func);
+      int mstatus = munmap (old, oldFullSize); // XXX ???
+      if (mstatus != 0) ohana_memabort ("failed to reallocate memory (%s, %d, %s)\n", file, line, func);
+    } else {
+      // mmap to mmap
+      new = (OhanaMemblock *) realloc (old, fullSize);
+      if (new == NULL) ohana_memabort ("failed to reallocate memory (%s, %d, %s)\n", file, line, func);
+    }
+  }
   char *ptr_new = (char *) (new + 1);
 # endif
@@ -217,4 +311,5 @@
 }
 
+// XXX this function is only used for memory allocated outside of the ohana_allocate system
 void real_free (void *in) {
 
@@ -237,4 +332,5 @@
   ref = (OhanaMemblock *) in - 1;
   if (!ref->nextBlock && !ref->prevBlock && (Nblock > 1)) ohana_memabort ("orphan block?? (%s@%d : %s)\n", file, line, func);
+  size_t fullSize = sizeof(OhanaMemblock) + ref->size + 2*sizeof(void *);   // total size is : memblock + data + endpost
 
   if (ref->freed) ohana_memabort ("memory already freed (%s, %d, %s [%d bytes])\n", ref->file, ref->line, ref->func, ref->size);
@@ -291,5 +387,11 @@
 # if (!TEST_SAVE_FREE_BLOCKS)
   memset (ref, 0x7f, sizeof(OhanaMemblock));
-  free (ref);
+  if (USE_MMAP_LOCAL && (fullSize > USE_MMAP_SIZE)) {
+    fprintf (stderr, "** munmap %ld (%s, %d, %s)\n", fullSize, file, line, func);
+    int mstatus = munmap (ref, fullSize);
+    if (mstatus != 0) ohana_memabort ("failed to free memory (%s, %d, %s)\n", file, line, func);
+  } else {
+    free (ref);
+  }
 # endif
 
