Add options to use mmap or electric fence to check memory accesses, and fix a few memory access violations.

git-svn-id: https://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk@1294008 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/configure.ac b/configure.ac
index cb85c39..6adf807 100644
--- a/configure.ac
+++ b/configure.ac
@@ -123,7 +123,6 @@
   else
     cxxflags="${cxxflags} -O2 -Wlogical-op -Wconversion"
   fi
-  ldflags="${ldflags} -pg"
   AM_CONDITIONAL([WANT_MAINTAINER_MODE], true)
   AC_DEFINE([WANT_MAINTAINER_MODE], 1, [compile with debugging and compile-time warnings])
 else
@@ -158,6 +157,47 @@
   AM_CONDITIONAL([WANT_PROFILING], false)
 fi
 
+# Enable memory checking with electric fence.
+AC_MSG_CHECKING([whether to enable electric fence])
+AC_ARG_ENABLE(efence, [AS_HELP_STRING([--enable-efence], [link with electric fence [default=no]])],
+[ case "${enableval}" in
+  no)
+    AC_MSG_RESULT(no)
+    ;;
+  *)
+    AC_MSG_RESULT(yes)
+    want_efence=true
+    ;;
+  esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_efence}" = "true"; then
+  ldflags="${ldflags} -lefence"
+  AM_CONDITIONAL([WANT_EFENCE], true)
+  AC_DEFINE([WANT_EFENCE], 1, [link with electric fence])
+else
+  AM_CONDITIONAL([WANT_EFENCE], false)
+fi
+
+# Enable usage of mmap for memory allocation.
+AC_MSG_CHECKING([whether to use mmap for memory allocation])
+AC_ARG_ENABLE(malloc-mmap, [AS_HELP_STRING([--enable-malloc-mmap], [use mmap for memory allocation [default=no]])],
+[ case "${enableval}" in
+  no)
+    AC_MSG_RESULT(no)
+    ;;
+  *)
+    AC_MSG_RESULT(yes)
+    want_malloc_mmap=true
+    ;;
+  esac ],
+[ AC_MSG_RESULT(no)])
+if test "${want_efence}" = "true"; then
+  AM_CONDITIONAL([WANT_MALLOC_MMAP], true)
+  AC_DEFINE([WANT_MALLOC_MMAP], 1, [use mmap for memory allocation])
+else
+  AM_CONDITIONAL([WANT_MALLOC_MMAP], false)
+fi
+
 # Enable multi-threading support.
 AC_MSG_CHECKING([whether to compile for multi-threaded execution])
 AC_ARG_ENABLE(threads, [AS_HELP_STRING([--enable-threads], [compile for multi-threaded execution [default=no]])],
diff --git a/etc/memgrind b/etc/memgrind
index 6fbb76b..079adca 100755
--- a/etc/memgrind
+++ b/etc/memgrind
@@ -19,5 +19,5 @@
 
 # Run valgrind to analyze memory usage and track memory leaks
 
-valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=40 --track-fds=yes $* 2>&1 | tee memgrind.log
+valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=40 --track-fds=yes --trace-children=yes $* 2>&1 | tee memgrind.log
 
diff --git a/kernel/gc.hpp b/kernel/gc.hpp
index 28ca80e..59947dd 100644
--- a/kernel/gc.hpp
+++ b/kernel/gc.hpp
@@ -26,6 +26,10 @@
  * Garbage collected memory management, using APR memory pools.
  */
 
+#ifdef WANT_MALLOC_MMAP
+#include <sys/mman.h>
+#include <malloc.h>
+#endif
 #include <stdlib.h>
 #include <apr_general.h>
 #include <apr_pools.h>
@@ -112,6 +116,16 @@
 };
 
 /**
+ * Initialize APR.
+ */
+class gc_apr_context_t {
+public:
+    gc_apr_context_t() {
+        apr_initialize();
+    }
+} gc_apr_context;
+
+/**
  * Garbage collected APR memory pool.
  */
 class gc_pool {
@@ -161,21 +175,13 @@
  * Destroy a memory pool.
  */
 const bool destroy(const gc_pool& p) {
+    if (pool(p) == NULL)
+        return false;
     apr_pool_destroy(pool(p));
     return true;
 }
 
 /**
- * Initialize APR.
- */
-class gc_apr_context_t {
-public:
-    gc_apr_context_t() {
-        apr_initialize();
-    }
-} gc_apr_context;
-
-/**
  * Maintain a stack of memory pools.
  */
 #ifdef WANT_THREADS
@@ -273,7 +279,7 @@
  * register a cleanup callback for it.
  */
 template<typename T> apr_status_t gc_pool_cleanup(void* v) {
-    T* t = static_cast<T*>(v);
+    T* t = (T*)v;
     t->~T();
     return APR_SUCCESS;
 }
@@ -282,7 +288,7 @@
     void* gc_new_ptr = apr_palloc(p, sizeof(T));
     assertOrFail(gc_new_ptr != NULL);
     apr_pool_cleanup_register(p, gc_new_ptr, gc_pool_cleanup<T>, apr_pool_cleanup_null) ;
-    return static_cast<T*>(gc_new_ptr);
+    return (T*)(gc_new_ptr);
 }
 
 template<typename T> T* gc_new(const gc_pool& p) {
@@ -334,42 +340,112 @@
 /**
  * Pool based equivalent of the standard malloc function.
  */
-void* gc_malloc(size_t n) {
-    size_t* gc_malloc_ptr = static_cast<size_t*>(apr_palloc(gc_current_pool(), sizeof(size_t) + n));
-    assertOrFail(gc_malloc_ptr != NULL);
-    *gc_malloc_ptr = n;
-    return gc_malloc_ptr + 1;
+void* gc_pool_malloc(size_t n) {
+    size_t* ptr = static_cast<size_t*>(apr_palloc(gc_current_pool(), sizeof(size_t) + n));
+    assertOrFail(ptr != NULL);
+    *ptr = n;
+    return ptr + 1;
 }
 
 /**
  * Pool based equivalent of the standard realloc function.
  */
-void* gc_realloc(void* ptr, size_t n) {
+void* gc_pool_realloc(void* ptr, size_t n) {
     size_t size = *(static_cast<size_t*>(ptr) - 1);
-    size_t* gc_realloc_ptr = static_cast<size_t*>(apr_palloc(gc_current_pool(), sizeof(size_t) + n));
-    assertOrFail(gc_realloc_ptr != NULL);
-    *gc_realloc_ptr = n;
-    memcpy(gc_realloc_ptr + 1, ptr, size < n? size : n);
-    return gc_realloc_ptr + 1;
+    size_t* rptr = static_cast<size_t*>(apr_palloc(gc_current_pool(), sizeof(size_t) + n));
+    assertOrFail(rptr != NULL);
+    *rptr = n;
+    memcpy(rptr + 1, ptr, size < n? size : n);
+    return rptr + 1;
 }
 
 /**
  * Pool based equivalent of the standard free function.
  */
-void gc_free(unused void* ptr) {
+void gc_pool_free(unused void* ptr) {
     // Memory allocated from a pool is freed when the pool is freed
 }
 
 /**
  * Pool based equivalent of the standard strdup function.
  */
-char* gc_strdup(const char* str) {
-    char* gc_strdup_ptr = static_cast<char*>(gc_malloc(strlen(str) + 1));
-    assertOrFail(gc_strdup_ptr != NULL);
-    strcpy(gc_strdup_ptr, str);
-    return gc_strdup_ptr;
+char* gc_pool_strdup(const char* str) {
+    char* dptr = static_cast<char*>(gc_pool_malloc(strlen(str) + 1));
+    assertOrFail(dptr != NULL);
+    strcpy(dptr, str);
+    return dptr;
 }
 
+#ifdef WANT_MALLOC_MMAP
+
+/**
+ * Mmap based memory allocation functions.
+ */
+
+/**
+ * Mmap based equivalent of the standard malloc function.
+ */
+void* gc_mmap_malloc(size_t n, unused const void* caller) {
+    //printf("gc_mmap_malloc %d", n);
+    size_t* ptr = static_cast<size_t*>(mmap(NULL, sizeof(size_t) + n, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
+    assertOrFail(ptr != NULL);
+    *ptr = n;
+    //printf(" %p\n", ptr + 1);
+    return ptr + 1;
 }
 
+/**
+ * Mmap based equivalent of the standard realloc function.
+ */
+void* gc_mmap_realloc(void* ptr, size_t n, const void* caller) {
+    if (ptr == NULL)
+        return gc_mmap_malloc(n, caller);;
+    //printf("gc_mmap_realloc %p %d", ptr, n);
+    size_t size = *(static_cast<size_t*>(ptr) - 1);
+    size_t* rptr = static_cast<size_t*>(mremap(static_cast<size_t*>(ptr) - 1, sizeof(size_t) + size, sizeof(size_t) + n, MREMAP_MAYMOVE, NULL));
+    assertOrFail(rptr != NULL);
+    *rptr = n;
+    //printf(" %p\n", rptr + 1);
+    return rptr + 1;
+}
+
+/**
+ * Mmap based equivalent of the standard free function.
+ */
+void gc_mmap_free(void* ptr, unused const void* caller) {
+    //printf("gc_mmap_free %p\n", ptr);
+    if (ptr == NULL)
+        return;
+    size_t size = *(static_cast<size_t*>(ptr) - 1);
+    munmap(static_cast<size_t*>(ptr) - 1, sizeof(size_t) + size);
+}
+
+/**
+ * Mmap based equivalent of the standard memalign function.
+ */
+void* gc_mmap_memalign(unused size_t alignment, size_t n, unused const void* caller) {
+    //printf("gc_mmap_memalign %d %d\n", alignment, n);
+    return gc_mmap_malloc(n, caller);
+}
+
+/**
+ * Install the mmap based memory allocation functions.
+ */
+void gc_mmap_init_hook(void) {
+    __malloc_hook = gc_mmap_malloc;
+    __realloc_hook = gc_mmap_realloc;
+    __free_hook = gc_mmap_free;
+    __memalign_hook = gc_mmap_memalign;
+}
+                                          
+#endif
+
+}
+
+#ifdef WANT_MALLOC_MMAP
+
+void (*__malloc_initialize_hook)(void) = tuscany::gc_mmap_init_hook;
+
+#endif
+
 #endif /* tuscany_gc_hpp */
diff --git a/kernel/mem-test.cpp b/kernel/mem-test.cpp
index b1164a5..e9a2f85 100644
--- a/kernel/mem-test.cpp
+++ b/kernel/mem-test.cpp
@@ -103,7 +103,7 @@
 };
 
 bool testPoolAllocPerf() {
-    const int count = 100000;
+    const int count = 10000;
     const lambda<bool()> pl = poolAllocPerf(count);
     maxElements = 0;
     cout << "Memory pool alloc test " << (time(pl, 1, 1) / count) << " ms" << endl;
@@ -139,7 +139,7 @@
 };
 
 bool testStdAllocPerf() {
-    const int count = 100000;
+    const int count = 10000;
     const lambda<bool()> sl = stdAllocPerf(count);
     maxElements = 0;
     cout << "Memory standard alloc test " << (time(sl, 1, 1) / count) << " ms" << endl;
diff --git a/kernel/string-test.cpp b/kernel/string-test.cpp
index f2f21f6..e691d93 100644
--- a/kernel/string-test.cpp
+++ b/kernel/string-test.cpp
@@ -153,7 +153,7 @@
     memset(charBuffer, 'A', 16384);
     charBuffer[16384] = '\0';
 
-    const int count = 100000;
+    const int count = 10000;
     {
         const lambda<bool()> a16 = addStrings(16);
         cout << "string test " << time(a16, 5, count) << " ms" << endl;
diff --git a/kernel/xml.hpp b/kernel/xml.hpp
index 1f1c664..b530932 100644
--- a/kernel/xml.hpp
+++ b/kernel/xml.hpp
@@ -51,12 +51,11 @@
 public:
     XMLParser() {
         debug("xml::XMLParser");
-        xmlMemSetup(gc_free, gc_malloc, gc_realloc, gc_strdup);
+        xmlMemSetup(gc_pool_free, gc_pool_malloc, gc_pool_realloc, gc_pool_strdup);
         xmlInitParser();
     }
 
     ~XMLParser() {
-        debug("xml::~XMLParser");
     }
 } xmlParser;
 
@@ -80,7 +79,6 @@
     }
 
     ~XMLReader() {
-        debug("xml::~XMLReader");
         if (!owner)
             return;
         xmlTextReaderClose(xml);
diff --git a/modules/java/eval.hpp b/modules/java/eval.hpp
index a73c84c..1e119aa 100644
--- a/modules/java/eval.hpp
+++ b/modules/java/eval.hpp
@@ -153,7 +153,6 @@
     }
 
     ~JavaRuntime() {
-        debug("java::~javaruntime");
     }
 
     JavaVM* jvm;
diff --git a/modules/json/json-test.cpp b/modules/json/json-test.cpp
index ac68d75..61aac4e 100644
--- a/modules/json/json-test.cpp
+++ b/modules/json/json-test.cpp
@@ -123,7 +123,8 @@
         istringstream is(str(wos));
         const list<string> il = streamList(is);
         const list<value> r = elementsToValues(content(readJSON(il, cx)));
-        assert(r == l);
+        const list<value> l2 = mklist<value>(list<value>() + "fruit" + (list<value>() + string("Apple") + string("Orange")));
+        assert(r == l2);
     }
     return true;
 }
diff --git a/modules/opencl/eval.hpp b/modules/opencl/eval.hpp
index ef0e028..35eb6a3 100644
--- a/modules/opencl/eval.hpp
+++ b/modules/opencl/eval.hpp
@@ -222,7 +222,6 @@
     }
 
     ~OpenCLContext() {
-        debug("opencl::~OpenCLContext");
         for (cl_uint i = 0; i < ndevs; i++) {
             if (cq[i] != 0)
                 clReleaseCommandQueue(cq[i]);
diff --git a/modules/python/eval.hpp b/modules/python/eval.hpp
index ed22fb2..41f45ac 100644
--- a/modules/python/eval.hpp
+++ b/modules/python/eval.hpp
@@ -96,7 +96,6 @@
     }
 
     ~PythonRuntime() {
-        debug("python::~pythonruntime");
     }
 
 private:
diff --git a/modules/server/client-test.hpp b/modules/server/client-test.hpp
index 2dab7b6..2207127 100644
--- a/modules/server/client-test.hpp
+++ b/modules/server/client-test.hpp
@@ -85,8 +85,9 @@
 const bool testEval() {
     gc_scoped_pool pool;
     http::CURLSession ch("", "", "", "");
-    const value val = content(http::evalExpr(mklist<value>(string("echo"), string("Hello")), testURI, ch));
-    assert(val == string("Hello"));
+    const failable<value> r = http::evalExpr(mklist<value>(string("echo"), string("Hello")), testURI, ch);
+    assert(hasContent(r));
+    assert(content(r) == string("Hello"));
     return true;
 }
 
@@ -96,8 +97,9 @@
     evalLoop(const string& uri, http::CURLSession& ch) : uri(uri), ch(ch) {
     }
     const bool operator()() const {
-        const value val = content(http::evalExpr(mklist<value>(string("echo"), string("Hello")), uri, ch));
-        assert(val == string("Hello"));
+        const failable<value> r = http::evalExpr(mklist<value>(string("echo"), string("Hello")), uri, ch);
+        assert(hasContent(r));
+        assert(content(r) == string("Hello"));
         return true;
     }
 };
@@ -111,8 +113,9 @@
     blobEvalLoop(const string& uri, http::CURLSession& ch) : uri(uri), ch(ch) {
     }
     const bool operator()() const {
-        const value val = content(http::evalExpr(mklist<value>(string("echo"), blobs), uri, ch));
-        assert(val == blobs);
+        const failable<value> r = content(http::evalExpr(mklist<value>(string("echo"), blobs), uri, ch));
+        assert(hasContent(r));
+        assert(content(r) == blobs);
         return true;
     }
 };
@@ -227,12 +230,12 @@
 
 struct postThreadLoop {
     const lambda<bool()> l;
+    worker& w;
     const int threads;
-    const gc_ptr<worker> w;
-    postThreadLoop(const lambda<bool()>& l, const int threads) : l(l), threads(threads), w(new (gc_new<worker>()) worker(threads)) {
+    postThreadLoop(const lambda<bool()>& l, worker& w, const int threads) : l(l), w(w), threads(threads) {
     }
     const bool operator()() const {
-        list<future<bool> > r = startPost(*w, threads, l);
+        list<future<bool> > r = startPost(w, threads, l);
         checkPost(r);
         return true;
     }
@@ -242,6 +245,7 @@
     gc_scoped_pool pool;
     const int count = 50;
     const int threads = 10;
+    worker w(threads);
 
     const list<value> i = list<value>() + "content" + (list<value>() + "item"
             + (list<value>() + "name" + string("Apple"))
@@ -252,7 +256,7 @@
             + i);
 
     const lambda<bool()> pl= curry(lambda<bool(const string, const int, const value)>(postThread), testURI, count, val);
-    const lambda<bool()> ptl = postThreadLoop(pl, threads);
+    const lambda<bool()> ptl = postThreadLoop(pl, w, threads);
     double t = time(ptl, 0, 1) / (threads * count);
     cout << "ATOMPub POST thread test " << t << " ms" << endl;