Merge "More debug malloc fixes."
diff --git a/libc/bionic/debug_format.cpp b/libc/bionic/debug_format.cpp
index e8d6a45..eeed3ac 100644
--- a/libc/bionic/debug_format.cpp
+++ b/libc/bionic/debug_format.cpp
@@ -460,6 +460,9 @@
         if (c == 's') {
             /* string */
             str = va_arg(args, const char*);
+            if (str == NULL) {
+                str = "(null)";
+            }
         } else if (c == 'c') {
             /* character */
             /* NOTE: char is promoted to int when passed through the stack */
diff --git a/libc/bionic/debug_stacktrace.cpp b/libc/bionic/debug_stacktrace.cpp
index 4b080a4..5c82205 100644
--- a/libc/bionic/debug_stacktrace.cpp
+++ b/libc/bionic/debug_stacktrace.cpp
@@ -47,7 +47,7 @@
 static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) {
   stack_crawl_state_t* state = static_cast<stack_crawl_state_t*>(arg);
   if (state->count) {
-    intptr_t ip = (intptr_t)_Unwind_GetIP(context);
+    uintptr_t ip = _Unwind_GetIP(context);
     if (ip) {
       state->addrs[0] = ip;
       state->addrs++;
@@ -60,7 +60,7 @@
   return _URC_END_OF_STACK;
 }
 
-__LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries) {
+__LIBC_HIDDEN__ int get_backtrace(uintptr_t* addrs, size_t max_entries) {
   stack_crawl_state_t state;
   state.count = max_entries;
   state.addrs = addrs;
@@ -68,8 +68,8 @@
   return max_entries - state.count;
 }
 
-__LIBC_HIDDEN__ void log_backtrace(mapinfo_t* map_info, intptr_t* addrs, size_t c) {
-  intptr_t self_bt[16];
+__LIBC_HIDDEN__ void log_backtrace(mapinfo_t* map_info, uintptr_t* addrs, size_t c) {
+  uintptr_t self_bt[16];
   if (addrs == NULL) {
     c = get_backtrace(self_bt, 16);
     addrs = self_bt;
@@ -101,7 +101,7 @@
       }
       if (symbol) {
         __libc_format_log(ANDROID_LOG_ERROR, "libc", "          #%02d  pc %08x  %s (%s+0x%x)",
-                          index, rel_pc, soname, symbol, addrs[i] - (intptr_t)offset);
+                          index, rel_pc, soname, symbol, addrs[i] - (uintptr_t) offset);
       } else {
         __libc_format_log(ANDROID_LOG_ERROR, "libc", "          #%02d  pc %08x  %s",
                           index, rel_pc, soname);
diff --git a/libc/bionic/debug_stacktrace.h b/libc/bionic/debug_stacktrace.h
index 3c66ea6..800a172 100644
--- a/libc/bionic/debug_stacktrace.h
+++ b/libc/bionic/debug_stacktrace.h
@@ -34,12 +34,12 @@
 
 struct stack_crawl_state_t {
   size_t count;
-  intptr_t* addrs;
+  uintptr_t* addrs;
 };
 
 struct mapinfo_t;
 
-__LIBC_HIDDEN__ int get_backtrace(intptr_t* stack_frames, size_t max_entries);
-__LIBC_HIDDEN__ void log_backtrace(mapinfo_t* map_info, intptr_t* stack_frames, size_t frame_count);
+__LIBC_HIDDEN__ int get_backtrace(uintptr_t* stack_frames, size_t max_entries);
+__LIBC_HIDDEN__ void log_backtrace(mapinfo_t* map_info, uintptr_t* stack_frames, size_t frame_count);
 
 #endif /* DEBUG_STACKTRACE_H */
diff --git a/libc/bionic/malloc_debug_check.cpp b/libc/bionic/malloc_debug_check.cpp
index 7b6a536..d366b56 100644
--- a/libc/bionic/malloc_debug_check.cpp
+++ b/libc/bionic/malloc_debug_check.cpp
@@ -78,9 +78,9 @@
     uint32_t tag;
     hdr_t* prev;
     hdr_t* next;
-    intptr_t bt[MAX_BACKTRACE_DEPTH];
+    uintptr_t bt[MAX_BACKTRACE_DEPTH];
     int bt_depth;
-    intptr_t freed_bt[MAX_BACKTRACE_DEPTH];
+    uintptr_t freed_bt[MAX_BACKTRACE_DEPTH];
     int freed_bt_depth;
     size_t size;
     char front_guard[FRONT_GUARD_LEN];
@@ -102,7 +102,7 @@
     return reinterpret_cast<hdr_t*>(user) - 1;
 }
 
-static unsigned num;
+static unsigned gAllocatedBlockCount;
 static hdr_t *tail;
 static hdr_t *head;
 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
@@ -181,7 +181,7 @@
     hdr->size = size;
     init_front_guard(hdr);
     init_rear_guard(hdr);
-    num++;
+    ++gAllocatedBlockCount;
     add_locked(hdr, &tail, &head);
 }
 
@@ -192,7 +192,7 @@
 
     ScopedPthreadMutexLocker locker(&lock);
     del_locked(hdr, &tail, &head);
-    num--;
+    --gAllocatedBlockCount;
     return 0;
 }
 
@@ -298,7 +298,7 @@
 
 static inline int del_leak(hdr_t *hdr, int *safe) {
     ScopedPthreadMutexLocker locker(&lock);
-    return del_and_check_locked(hdr, &tail, &head, &num, safe);
+    return del_and_check_locked(hdr, &tail, &head, &gAllocatedBlockCount, safe);
 }
 
 static inline void add_to_backlog(hdr_t *hdr) {
@@ -342,7 +342,7 @@
     hdr_t* hdr = meta(ptr);
 
     if (del(hdr) < 0) {
-        intptr_t bt[MAX_BACKTRACE_DEPTH];
+        uintptr_t bt[MAX_BACKTRACE_DEPTH];
         int depth;
         depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH);
         if (hdr->tag == BACKLOG_TAG) {
@@ -387,7 +387,7 @@
     hdr_t* hdr = meta(ptr);
 
     if (del(hdr) < 0) {
-        intptr_t bt[MAX_BACKTRACE_DEPTH];
+        uintptr_t bt[MAX_BACKTRACE_DEPTH];
         int depth;
         depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH);
         if (hdr->tag == BACKLOG_TAG) {
@@ -442,28 +442,36 @@
 }
 
 static void heaptracker_free_leaked_memory() {
-    size_t total = num;
-    if (num) {
-        log_message("+++ Leaked allocations: %d\n", num);
-    }
+  if (gAllocatedBlockCount == 0) {
+    return;
+  }
 
-    hdr_t *del = NULL;
-    while (head) {
-        int safe;
-        del = head;
-        log_message("+++ Leaked block of size %d at %p (leak %d of %d)\n",
-                del->size, user(del), 1 + total - num, total);
-        if (del_leak(del, &safe)) {
-            /* safe == 1, because the allocation is valid */
-            log_backtrace(gMapInfo, del->bt, del->bt_depth);
-        }
-    }
+  // Use /proc/self/exe link to obtain the program name for logging
+  // purposes. If it's not available, we set it to "<unknown>".
+  char exe[PATH_MAX];
+  int count;
+  if ((count = readlink("/proc/self/exe", exe, sizeof(exe) - 1)) == -1) {
+    strlcpy(exe, "<unknown>", sizeof(exe));
+  } else {
+    exe[count] = '\0';
+  }
 
-//  log_message("+++ DELETING %d BACKLOGGED ALLOCATIONS\n", backlog_num);
-    while (backlog_head) {
-        del = backlog_tail;
-        del_from_backlog(del);
+  size_t index = 1;
+  const size_t total = gAllocatedBlockCount;
+  while (head != NULL) {
+    int safe;
+    hdr_t* block = head;
+    log_message("+++ %s leaked block of size %d at %p (leak %d of %d)",
+                exe, block->size, user(block), index++, total);
+    if (del_leak(block, &safe)) {
+      /* safe == 1, because the allocation is valid */
+      log_backtrace(gMapInfo, block->bt, block->bt_depth);
     }
+  }
+
+  while (backlog_head != NULL) {
+    del_from_backlog(backlog_tail);
+  }
 }
 
 /* Initializes malloc debugging framework.
diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp
index 6e1ee70..a27de20 100644
--- a/libc/bionic/malloc_debug_common.cpp
+++ b/libc/bionic/malloc_debug_common.cpp
@@ -148,7 +148,7 @@
     }
 
     // XXX: the protocol doesn't allow variable size for the stack trace (yet)
-    *infoSize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * BACKTRACE_SIZE);
+    *infoSize = (sizeof(size_t) * 2) + (sizeof(uintptr_t) * BACKTRACE_SIZE);
     *overallSize = *infoSize * gHashTable.count;
     *backtraceSize = BACKTRACE_SIZE;
 
@@ -167,7 +167,7 @@
     const int count = gHashTable.count;
     for (int i = 0 ; i < count ; ++i) {
         HashEntry* entry = list[i];
-        size_t entrySize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * entry->numEntries);
+        size_t entrySize = (sizeof(size_t) * 2) + (sizeof(uintptr_t) * entry->numEntries);
         if (entrySize < *infoSize) {
             /* we're writing less than a full entry, clear out the rest */
             memset(head + entrySize, 0, *infoSize - entrySize);
@@ -377,8 +377,10 @@
     }
 
     // mksh is way too leaky. http://b/7291287.
-    if (debug_level >= 10 && strcmp(__progname, "sh") == 0) {
-        return;
+    if (debug_level >= 10) {
+        if (strcmp(__progname, "sh") == 0 || strcmp(__progname, "/system/bin/sh") == 0) {
+            return;
+        }
     }
 
     // Choose the appropriate .so for the requested debug level.
diff --git a/libc/bionic/malloc_debug_common.h b/libc/bionic/malloc_debug_common.h
index 3d12f87..e15ccd0 100644
--- a/libc/bionic/malloc_debug_common.h
+++ b/libc/bionic/malloc_debug_common.h
@@ -57,7 +57,7 @@
     // fields above "size" are NOT sent to the host
     size_t size;
     size_t allocations;
-    intptr_t backtrace[0];
+    uintptr_t backtrace[0];
 };
 
 struct HashTable {
diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp
index 68b6ae2..9e63a86 100644
--- a/libc/bionic/malloc_debug_leak.cpp
+++ b/libc/bionic/malloc_debug_leak.cpp
@@ -90,7 +90,7 @@
 // Hash Table functions
 // =============================================================================
 
-static uint32_t get_hash(intptr_t* backtrace, size_t numEntries) {
+static uint32_t get_hash(uintptr_t* backtrace, size_t numEntries) {
     if (backtrace == NULL) return 0;
 
     int hash = 0;
@@ -103,7 +103,7 @@
 }
 
 static HashEntry* find_entry(HashTable* table, int slot,
-        intptr_t* backtrace, size_t numEntries, size_t size) {
+                             uintptr_t* backtrace, size_t numEntries, size_t size) {
     HashEntry* entry = table->slots[slot];
     while (entry != NULL) {
         //debug_log("backtrace: %p, entry: %p entry->backtrace: %p\n",
@@ -113,7 +113,7 @@
          * including the flag bits.
          */
         if (entry->size == size && entry->numEntries == numEntries &&
-                !memcmp(backtrace, entry->backtrace, numEntries * sizeof(intptr_t))) {
+                !memcmp(backtrace, entry->backtrace, numEntries * sizeof(uintptr_t))) {
             return entry;
         }
 
@@ -123,7 +123,7 @@
     return NULL;
 }
 
-static HashEntry* record_backtrace(intptr_t* backtrace, size_t numEntries, size_t size) {
+static HashEntry* record_backtrace(uintptr_t* backtrace, size_t numEntries, size_t size) {
     size_t hash = get_hash(backtrace, numEntries);
     size_t slot = hash % HASHTABLE_SIZE;
 
@@ -142,7 +142,7 @@
         entry->allocations++;
     } else {
         // create a new entry
-        entry = static_cast<HashEntry*>(dlmalloc(sizeof(HashEntry) + numEntries*sizeof(intptr_t)));
+        entry = static_cast<HashEntry*>(dlmalloc(sizeof(HashEntry) + numEntries*sizeof(uintptr_t)));
         if (!entry) {
             return NULL;
         }
@@ -153,7 +153,7 @@
         entry->numEntries = numEntries;
         entry->size = size;
 
-        memcpy(entry->backtrace, backtrace, numEntries * sizeof(intptr_t));
+        memcpy(entry->backtrace, backtrace, numEntries * sizeof(uintptr_t));
 
         gHashTable.slots[slot] = entry;
 
@@ -272,7 +272,7 @@
     if (base != NULL) {
         ScopedPthreadMutexLocker locker(&gAllocationsMutex);
 
-        intptr_t backtrace[BACKTRACE_SIZE];
+        uintptr_t backtrace[BACKTRACE_SIZE];
         size_t numEntries = get_backtrace(backtrace, BACKTRACE_SIZE);
 
         AllocationEntry* header = reinterpret_cast<AllocationEntry*>(base);
diff --git a/libc/bionic/pthread_debug.cpp b/libc/bionic/pthread_debug.cpp
index 7d98d10..ac81837 100644
--- a/libc/bionic/pthread_debug.cpp
+++ b/libc/bionic/pthread_debug.cpp
@@ -180,8 +180,8 @@
 struct MutexInfo;
 
 typedef struct CallStack {
-    intptr_t    depth;
-    intptr_t*   addrs;
+    uintptr_t    depth;
+    uintptr_t*   addrs;
 } CallStack;
 
 typedef struct MutexInfo* MutexInfoListEntry;
@@ -222,7 +222,7 @@
     CallStackList       stacks;
     // call stack when this lock was acquired last
     int                 stackDepth;
-    intptr_t            stackTrace[STACK_TRACE_DEPTH];
+    uintptr_t           stackTrace[STACK_TRACE_DEPTH];
 } MutexInfo;
 
 static void growingListInit(GrowingList* list) {
@@ -285,10 +285,10 @@
 
 /****************************************************************************/
 
-static void dup_backtrace(CallStack* stack, size_t count, intptr_t const* addrs) {
+static void dup_backtrace(CallStack* stack, size_t count, uintptr_t const* addrs) {
     stack->depth = count;
-    stack->addrs = DbgAllocLocked<intptr_t>(count);
-    memcpy(stack->addrs, addrs, count * sizeof(intptr_t));
+    stack->addrs = DbgAllocLocked<uintptr_t>(count);
+    memcpy(stack->addrs, addrs, count * sizeof(uintptr_t));
 }
 
 /****************************************************************************/
@@ -343,7 +343,7 @@
 /****************************************************************************/
 
 static void callstackListAdd(CallStackList* pList,
-        int count, intptr_t const* addrs) {
+        int count, uintptr_t const* addrs) {
     growingListAdd(pList, sizeof(CallStackListEntry));
     dup_backtrace(&pList->stack[pList->count - 1], count, addrs);
 }
@@ -365,7 +365,7 @@
      */
     if (obj->historyMark) {
         int stackDepth;
-        intptr_t addrs[STACK_TRACE_DEPTH];
+        uintptr_t addrs[STACK_TRACE_DEPTH];
 
         /* Turn off prediction temporarily in this thread while logging */
         sPthreadDebugDisabledThread = gettid();