Fix debug malloc.

Previously the dynamically-loaded part of the debug malloc implementation
wanted to access hidden symbols in libc itself.

Bug: 15426546
Change-Id: I6a366ef626854d1af1d705ca24842817b1c02a19
diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp
index db3f995..19524bb 100644
--- a/libc/bionic/malloc_debug_common.cpp
+++ b/libc/bionic/malloc_debug_common.cpp
@@ -48,13 +48,48 @@
 
 #include "private/ScopedPthreadMutexLocker.h"
 
-/*
- * In a VM process, this is set to 1 after fork()ing out of zygote.
- */
+// In a VM process, this is set to 1 after fork()ing out of zygote.
 int gMallocLeakZygoteChild = 0;
 
-__LIBC_HIDDEN__ pthread_mutex_t g_allocations_mutex = PTHREAD_MUTEX_INITIALIZER;
-__LIBC_HIDDEN__ HashTable g_hash_table;
+static HashTable g_hash_table;
+
+// Support for malloc debugging.
+// Table for dispatching malloc calls, initialized with default dispatchers.
+static const MallocDebug __libc_malloc_default_dispatch __attribute__((aligned(32))) = {
+  Malloc(malloc), Malloc(free), Malloc(calloc), Malloc(realloc), Malloc(memalign), Malloc(malloc_usable_size),
+};
+
+// Selector of dispatch table to use for dispatching malloc calls.
+static const MallocDebug* __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
+
+// Handle to shared library where actual memory allocation is implemented.
+// This library is loaded and memory allocation calls are redirected there
+// when libc.debug.malloc environment variable contains value other than
+// zero:
+// 1  - For memory leak detections.
+// 5  - For filling allocated / freed memory with patterns defined by
+//      CHK_SENTINEL_VALUE, and CHK_FILL_FREE macros.
+// 10 - For adding pre-, and post- allocation stubs in order to detect
+//      buffer overruns.
+// Note that emulator's memory allocation instrumentation is not controlled by
+// libc.debug.malloc value, but rather by emulator, started with -memcheck
+// option. Note also, that if emulator has started with -memcheck option,
+// emulator's instrumented memory allocation will take over value saved in
+// libc.debug.malloc. In other words, if emulator has started with -memcheck
+// option, libc.debug.malloc value is ignored.
+// Actual functionality for debug levels 1-10 is implemented in
+// libc_malloc_debug_leak.so, while functionality for emulator's instrumented
+// allocations is implemented in libc_malloc_debug_qemu.so and can be run inside
+// the emulator only.
+#if !defined(LIBC_STATIC)
+static void* libc_malloc_impl_handle = NULL;
+#endif
+
+
+// The value of libc.debug.malloc.
+#if !defined(LIBC_STATIC)
+static int g_malloc_debug_level = 0;
+#endif
 
 // =============================================================================
 // output functions
@@ -123,7 +158,7 @@
     }
     *totalMemory = 0;
 
-    ScopedPthreadMutexLocker locker(&g_allocations_mutex);
+    ScopedPthreadMutexLocker locker(&g_hash_table.lock);
 
     if (g_hash_table.count == 0) {
         *info = NULL;
@@ -204,17 +239,6 @@
     return Malloc(posix_memalign)(memptr, alignment, size);
 }
 
-// Support for malloc debugging.
-// Table for dispatching malloc calls, initialized with default dispatchers.
-extern const MallocDebug __libc_malloc_default_dispatch;
-const MallocDebug __libc_malloc_default_dispatch __attribute__((aligned(32))) =
-{
-    Malloc(malloc), Malloc(free), Malloc(calloc), Malloc(realloc), Malloc(memalign), Malloc(malloc_usable_size),
-};
-
-/* Selector of dispatch table to use for dispatching malloc calls. */
-const MallocDebug* __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
-
 extern "C" void* malloc(size_t bytes) {
     return __libc_malloc_dispatch->malloc(bytes);
 }
@@ -248,59 +272,19 @@
 #include <stdio.h>
 #include "private/libc_logging.h"
 
-/* Table for dispatching malloc calls, depending on environment. */
-static MallocDebug g_malloc_dispatch_table __attribute__((aligned(32))) = {
-    Malloc(malloc), Malloc(free), Malloc(calloc), Malloc(realloc), Malloc(memalign), Malloc(malloc_usable_size)
-};
-
-extern const char* __progname;
-
-/* Handle to shared library where actual memory allocation is implemented.
- * This library is loaded and memory allocation calls are redirected there
- * when libc.debug.malloc environment variable contains value other than
- * zero:
- * 1  - For memory leak detections.
- * 5  - For filling allocated / freed memory with patterns defined by
- *      CHK_SENTINEL_VALUE, and CHK_FILL_FREE macros.
- * 10 - For adding pre-, and post- allocation stubs in order to detect
- *      buffer overruns.
- * Note that emulator's memory allocation instrumentation is not controlled by
- * libc.debug.malloc value, but rather by emulator, started with -memcheck
- * option. Note also, that if emulator has started with -memcheck option,
- * emulator's instrumented memory allocation will take over value saved in
- * libc.debug.malloc. In other words, if emulator has started with -memcheck
- * option, libc.debug.malloc value is ignored.
- * Actual functionality for debug levels 1-10 is implemented in
- * libc_malloc_debug_leak.so, while functionality for emultor's instrumented
- * allocations is implemented in libc_malloc_debug_qemu.so and can be run inside
- * the emulator only.
- */
-static void* libc_malloc_impl_handle = NULL;
-
-/* This variable is set to the value of property libc.debug.malloc.backlog,
- * when the value of libc.debug.malloc = 10.  It determines the size of the
- * backlog we use to detect multiple frees.  If the property is not set, the
- * backlog length defaults to BACKLOG_DEFAULT_LEN.
- */
-__LIBC_HIDDEN__ unsigned int g_malloc_debug_backlog;
-#define BACKLOG_DEFAULT_LEN 100
-
-/* The value of libc.debug.malloc. */
-__LIBC_HIDDEN__ int g_malloc_debug_level;
-
 template<typename FunctionType>
 static void InitMallocFunction(void* malloc_impl_handler, FunctionType* func, const char* prefix, const char* suffix) {
     char symbol[128];
     snprintf(symbol, sizeof(symbol), "%s_%s", prefix, suffix);
     *func = reinterpret_cast<FunctionType>(dlsym(malloc_impl_handler, symbol));
     if (*func == NULL) {
-        error_log("%s: dlsym(\"%s\") failed", __progname, symbol);
+        error_log("%s: dlsym(\"%s\") failed", getprogname(), symbol);
     }
 }
 
 static void InitMalloc(void* malloc_impl_handler, MallocDebug* table, const char* prefix) {
     __libc_format_log(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n",
-                      __progname, g_malloc_debug_level, prefix);
+                      getprogname(), g_malloc_debug_level, prefix);
 
     InitMallocFunction<MallocDebugMalloc>(malloc_impl_handler, &table->malloc, prefix, "malloc");
     InitMallocFunction<MallocDebugFree>(malloc_impl_handler, &table->free, prefix, "free");
@@ -349,14 +333,14 @@
      * then exit.
      */
     if (__system_property_get("libc.debug.malloc.program", debug_program)) {
-        if (!strstr(__progname, debug_program)) {
+        if (!strstr(getprogname(), debug_program)) {
             return;
         }
     }
 
     // mksh is way too leaky. http://b/7291287.
     if (g_malloc_debug_level >= 10) {
-        if (strcmp(__progname, "sh") == 0 || strcmp(__progname, "/system/bin/sh") == 0) {
+        if (strcmp(getprogname(), "sh") == 0 || strcmp(getprogname(), "/system/bin/sh") == 0) {
             return;
         }
     }
@@ -365,35 +349,26 @@
     switch (g_malloc_debug_level) {
         case 1:
         case 5:
-        case 10: {
-            char debug_backlog[PROP_VALUE_MAX];
-            if (__system_property_get("libc.debug.malloc.backlog", debug_backlog)) {
-                g_malloc_debug_backlog = atoi(debug_backlog);
-                info_log("%s: setting backlog length to %d\n", __progname, g_malloc_debug_backlog);
-            }
-            if (g_malloc_debug_backlog == 0) {
-                g_malloc_debug_backlog = BACKLOG_DEFAULT_LEN;
-            }
+        case 10:
             so_name = "libc_malloc_debug_leak.so";
             break;
-        }
         case 20:
             // Quick check: debug level 20 can only be handled in emulator.
             if (!qemu_running) {
                 error_log("%s: Debug level %d can only be set in emulator\n",
-                          __progname, g_malloc_debug_level);
+                          getprogname(), g_malloc_debug_level);
                 return;
             }
             // Make sure that memory checking has been enabled in emulator.
             if (!memcheck_enabled) {
                 error_log("%s: Memory checking is not enabled in the emulator\n",
-                          __progname);
+                          getprogname());
                 return;
             }
             so_name = "libc_malloc_debug_qemu.so";
             break;
         default:
-            error_log("%s: Debug level %d is unknown\n", __progname, g_malloc_debug_level);
+            error_log("%s: Debug level %d is unknown\n", getprogname(), g_malloc_debug_level);
             return;
     }
 
@@ -401,7 +376,7 @@
     void* malloc_impl_handle = dlopen(so_name, RTLD_LAZY);
     if (malloc_impl_handle == NULL) {
         error_log("%s: Missing module %s required for malloc debug level %d: %s",
-                  __progname, so_name, g_malloc_debug_level, dlerror());
+                  getprogname(), so_name, g_malloc_debug_level, dlerror());
         return;
     }
 
@@ -410,11 +385,11 @@
                                                                       "malloc_debug_initialize"));
     if (malloc_debug_initialize == NULL) {
         error_log("%s: Initialization routine is not found in %s\n",
-                  __progname, so_name);
+                  getprogname(), so_name);
         dlclose(malloc_impl_handle);
         return;
     }
-    if (malloc_debug_initialize() == -1) {
+    if (malloc_debug_initialize(&g_hash_table) == -1) {
         dlclose(malloc_impl_handle);
         return;
     }
@@ -427,7 +402,7 @@
                                                  "memcheck_initialize"));
         if (memcheck_initialize == NULL) {
             error_log("%s: memcheck_initialize routine is not found in %s\n",
-                      __progname, so_name);
+                      getprogname(), so_name);
             dlclose(malloc_impl_handle);
             return;
         }
@@ -438,44 +413,52 @@
         }
     }
 
-
     // Initialize malloc dispatch table with appropriate routines.
+    static MallocDebug malloc_dispatch_table __attribute__((aligned(32))) = {
+        Malloc(malloc),
+        Malloc(free),
+        Malloc(calloc),
+        Malloc(realloc),
+        Malloc(memalign),
+        Malloc(malloc_usable_size)
+    };
+
     switch (g_malloc_debug_level) {
         case 1:
-            InitMalloc(malloc_impl_handle, &g_malloc_dispatch_table, "leak");
+            InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "leak");
             break;
         case 5:
-            InitMalloc(malloc_impl_handle, &g_malloc_dispatch_table, "fill");
+            InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "fill");
             break;
         case 10:
-            InitMalloc(malloc_impl_handle, &g_malloc_dispatch_table, "chk");
+            InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "chk");
             break;
         case 20:
-            InitMalloc(malloc_impl_handle, &g_malloc_dispatch_table, "qemu_instrumented");
+            InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "qemu_instrumented");
             break;
         default:
             break;
     }
 
     // Make sure dispatch table is initialized
-    if ((g_malloc_dispatch_table.malloc == NULL) ||
-        (g_malloc_dispatch_table.free == NULL) ||
-        (g_malloc_dispatch_table.calloc == NULL) ||
-        (g_malloc_dispatch_table.realloc == NULL) ||
-        (g_malloc_dispatch_table.memalign == NULL) ||
-        (g_malloc_dispatch_table.malloc_usable_size == NULL)) {
+    if ((malloc_dispatch_table.malloc == NULL) ||
+        (malloc_dispatch_table.free == NULL) ||
+        (malloc_dispatch_table.calloc == NULL) ||
+        (malloc_dispatch_table.realloc == NULL) ||
+        (malloc_dispatch_table.memalign == NULL) ||
+        (malloc_dispatch_table.malloc_usable_size == NULL)) {
         error_log("%s: some symbols for libc.debug.malloc level %d were not found (see above)",
-                  __progname, g_malloc_debug_level);
+                  getprogname(), g_malloc_debug_level);
         dlclose(malloc_impl_handle);
     } else {
-        __libc_malloc_dispatch = &g_malloc_dispatch_table;
+        __libc_malloc_dispatch = &malloc_dispatch_table;
         libc_malloc_impl_handle = malloc_impl_handle;
     }
 }
 
 static void malloc_fini_impl() {
     // Our BSD stdio implementation doesn't close the standard streams, it only flushes them.
-    // And it doesn't do that until its atexit handler (_cleanup) is run, and we run first!
+    // And it doesn't do that until its atexit handler is run, and we run first!
     // It's great that other unclosed FILE*s show up as malloc leaks, but we need to manually
     // clean up the standard streams ourselves.
     fclose(stdin);
@@ -487,14 +470,11 @@
             reinterpret_cast<MallocDebugFini>(dlsym(libc_malloc_impl_handle,
                                                     "malloc_debug_finalize"));
         if (malloc_debug_finalize != NULL) {
-            malloc_debug_finalize();
+            malloc_debug_finalize(g_malloc_debug_level);
         }
     }
 }
 
-static pthread_once_t  malloc_init_once_ctl = PTHREAD_ONCE_INIT;
-static pthread_once_t  malloc_fini_once_ctl = PTHREAD_ONCE_INIT;
-
 #endif  // !LIBC_STATIC
 
 /* Initializes memory allocation framework.
@@ -502,21 +482,19 @@
  * in libc_init_static.c and libc_init_dynamic.c files.
  */
 extern "C" __LIBC_HIDDEN__ void malloc_debug_init() {
-    /* We need to initialize malloc iff we implement here custom
-     * malloc routines (i.e. USE_DL_PREFIX is defined) for libc.so */
 #if defined(USE_DL_PREFIX) && !defined(LIBC_STATIC)
-    if (pthread_once(&malloc_init_once_ctl, malloc_init_impl)) {
-        error_log("Unable to initialize malloc_debug component.");
-    }
+  static pthread_once_t malloc_init_once_ctl = PTHREAD_ONCE_INIT;
+  if (pthread_once(&malloc_init_once_ctl, malloc_init_impl)) {
+    error_log("Unable to initialize malloc_debug component.");
+  }
 #endif  // USE_DL_PREFIX && !LIBC_STATIC
 }
 
 extern "C" __LIBC_HIDDEN__ void malloc_debug_fini() {
-    /* We need to finalize malloc iff we implement here custom
-     * malloc routines (i.e. USE_DL_PREFIX is defined) for libc.so */
 #if defined(USE_DL_PREFIX) && !defined(LIBC_STATIC)
-    if (pthread_once(&malloc_fini_once_ctl, malloc_fini_impl)) {
-        error_log("Unable to finalize malloc_debug component.");
-    }
+  static pthread_once_t malloc_fini_once_ctl = PTHREAD_ONCE_INIT;
+  if (pthread_once(&malloc_fini_once_ctl, malloc_fini_impl)) {
+    error_log("Unable to finalize malloc_debug component.");
+  }
 #endif  // USE_DL_PREFIX && !LIBC_STATIC
 }