Mangle the pointers stored in PointerData.

The libmemunreachable library looks through memory to determine
if pointers are leaked. Unfortunately, the malloc debug code
stores the original pointer in data structures, so it looks like
pointers are still in use. The fix is to mangle the pointers
stored in memory so that it doesn't trick the library into thinking
they are live.

Test: All unit/system tests pass.
Test: Ran libmemunreachable and verified leaks show up.
Change-Id: Ic40a0a5ae73857cde936fd76895d88829686a643
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
index b982c0a..eaa0eb7 100644
--- a/libc/malloc_debug/PointerData.cpp
+++ b/libc/malloc_debug/PointerData.cpp
@@ -35,6 +35,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <functional>
 #include <mutex>
 #include <string>
 #include <unordered_map>
@@ -195,40 +196,41 @@
 }
 
 void PointerData::Add(const void* ptr, size_t pointer_size) {
-  uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
   size_t hash_index = 0;
   if (backtrace_enabled_) {
     hash_index = AddBacktrace(g_debug->config().backtrace_frames());
   }
 
   std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
-  pointers_[pointer] = PointerInfoType{PointerInfoType::GetEncodedSize(pointer_size), hash_index};
+  uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
+  pointers_[mangled_ptr] =
+      PointerInfoType{PointerInfoType::GetEncodedSize(pointer_size), hash_index};
 }
 
 void PointerData::Remove(const void* ptr) {
-  uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
   size_t hash_index;
   {
     std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
-    auto entry = pointers_.find(pointer);
+    uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
+    auto entry = pointers_.find(mangled_ptr);
     if (entry == pointers_.end()) {
       // Attempt to remove unknown pointer.
-      error_log("No tracked pointer found for 0x%" PRIxPTR, pointer);
+      error_log("No tracked pointer found for 0x%" PRIxPTR, DemanglePointer(mangled_ptr));
       return;
     }
     hash_index = entry->second.hash_index;
-    pointers_.erase(pointer);
+    pointers_.erase(mangled_ptr);
   }
 
   RemoveBacktrace(hash_index);
 }
 
 size_t PointerData::GetFrames(const void* ptr, uintptr_t* frames, size_t max_frames) {
-  uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
   size_t hash_index;
   {
     std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
-    auto entry = pointers_.find(pointer);
+    uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
+    auto entry = pointers_.find(mangled_ptr);
     if (entry == pointers_.end()) {
       return 0;
     }
@@ -274,7 +276,8 @@
 
 void PointerData::LogFreeError(const FreePointerInfoType& info, size_t max_cmp_bytes) {
   error_log(LOG_DIVIDER);
-  uint8_t* memory = reinterpret_cast<uint8_t*>(info.pointer);
+  uintptr_t pointer = DemanglePointer(info.mangled_ptr);
+  uint8_t* memory = reinterpret_cast<uint8_t*>(pointer);
   error_log("+++ ALLOCATION %p USED AFTER FREE", memory);
   uint8_t fill_free_value = g_debug->config().fill_free_value();
   for (size_t i = 0; i < max_cmp_bytes; i++) {
@@ -296,13 +299,14 @@
 
 void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
   size_t usable_size;
+  uintptr_t pointer = DemanglePointer(info.mangled_ptr);
   if (g_debug->HeaderEnabled()) {
     // Check to see if the tag data has been damaged.
-    Header* header = g_debug->GetHeader(reinterpret_cast<const void*>(info.pointer));
+    Header* header = g_debug->GetHeader(reinterpret_cast<const void*>(pointer));
     if (header->tag != DEBUG_FREE_TAG) {
       error_log(LOG_DIVIDER);
-      error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE",
-                info.pointer, header->tag);
+      error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE", pointer,
+                header->tag);
       error_log(LOG_DIVIDER);
       if (g_debug->config().options() & ABORT_ON_ERROR) {
         abort();
@@ -314,14 +318,14 @@
     }
     usable_size = header->usable_size;
   } else {
-    usable_size = g_dispatch->malloc_usable_size(reinterpret_cast<const void*>(info.pointer));
+    usable_size = g_dispatch->malloc_usable_size(reinterpret_cast<const void*>(pointer));
   }
 
   size_t bytes = (usable_size < g_debug->config().fill_on_free_bytes())
                      ? usable_size
                      : g_debug->config().fill_on_free_bytes();
   size_t max_cmp_bytes = bytes;
-  const uint8_t* memory = reinterpret_cast<const uint8_t*>(info.pointer);
+  const uint8_t* memory = reinterpret_cast<const uint8_t*>(pointer);
   while (bytes > 0) {
     size_t bytes_to_cmp = (bytes < g_cmp_mem.size()) ? bytes : g_cmp_mem.size();
     if (memcmp(memory, g_cmp_mem.data(), bytes_to_cmp) != 0) {
@@ -333,8 +337,6 @@
 }
 
 void* PointerData::AddFreed(const void* ptr) {
-  uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
-
   size_t hash_index = 0;
   size_t num_frames = g_debug->config().free_track_backtrace_num_frames();
   if (num_frames) {
@@ -348,10 +350,11 @@
     free_pointers_.pop_front();
     VerifyFreedPointer(info);
     RemoveBacktrace(info.hash_index);
-    last = reinterpret_cast<void*>(info.pointer);
+    last = reinterpret_cast<void*>(DemanglePointer(info.mangled_ptr));
   }
 
-  free_pointers_.emplace_back(FreePointerInfoType{pointer, hash_index});
+  uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
+  free_pointers_.emplace_back(FreePointerInfoType{mangled_ptr, hash_index});
   return last;
 }
 
@@ -361,7 +364,7 @@
     uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
     std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
     for (const auto& info : free_pointers_) {
-      if (info.pointer == pointer) {
+      if (DemanglePointer(info.mangled_ptr) == pointer) {
         hash_index = info.hash_index;
         break;
       }
@@ -388,6 +391,7 @@
   for (const auto& entry : pointers_) {
     FrameInfoType* frame_info = nullptr;
     std::vector<unwindstack::FrameData>* backtrace_info = nullptr;
+    uintptr_t pointer = DemanglePointer(entry.first);
     size_t hash_index = entry.second.hash_index;
     if (hash_index > kBacktraceEmptyIndex) {
       auto frame_entry = frames_.find(hash_index);
@@ -397,7 +401,7 @@
         // occurs after the hash_index and frame data have been added.
         // When removing a pointer, the pointer is deleted before the frame
         // data.
-        error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
+        error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", pointer, hash_index);
       } else {
         frame_info = &frame_entry->second;
       }
@@ -405,7 +409,7 @@
       if (g_debug->config().options() & BACKTRACE_FULL) {
         auto backtrace_entry = backtraces_info_.find(hash_index);
         if (backtrace_entry == backtraces_info_.end()) {
-          error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
+          error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", pointer, hash_index);
         } else {
           backtrace_info = &backtrace_entry->second;
         }
@@ -415,7 +419,7 @@
       continue;
     }
 
-    list->emplace_back(ListInfoType{entry.first, 1, entry.second.RealSize(),
+    list->emplace_back(ListInfoType{pointer, 1, entry.second.RealSize(),
                                     entry.second.ZygoteChildAlloc(), frame_info, backtrace_info});
   }
 
@@ -550,9 +554,9 @@
 }
 
 bool PointerData::Exists(const void* ptr) {
-  uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
   std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
-  return pointers_.count(pointer) != 0;
+  uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
+  return pointers_.count(mangled_ptr) != 0;
 }
 
 void PointerData::DumpLiveToFile(int fd) {
@@ -637,3 +641,10 @@
   free_pointer_mutex_.try_lock();
   free_pointer_mutex_.unlock();
 }
+
+void PointerData::IteratePointers(std::function<void(uintptr_t pointer)> fn) {
+  std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+  for (const auto entry : pointers_) {
+    fn(DemanglePointer(entry.first));
+  }
+}
diff --git a/libc/malloc_debug/PointerData.h b/libc/malloc_debug/PointerData.h
index 92d2653..97eec0a 100644
--- a/libc/malloc_debug/PointerData.h
+++ b/libc/malloc_debug/PointerData.h
@@ -33,6 +33,7 @@
 
 #include <atomic>
 #include <deque>
+#include <functional>
 #include <mutex>
 #include <string>
 #include <unordered_map>
@@ -99,7 +100,7 @@
 };
 
 struct FreePointerInfoType {
-  uintptr_t pointer;
+  uintptr_t mangled_ptr;
   size_t hash_index;
 };
 
@@ -134,16 +135,14 @@
   void PostForkParent();
   void PostForkChild();
 
+  static void IteratePointers(std::function<void(uintptr_t pointer)> fn);
+
   static size_t AddBacktrace(size_t num_frames);
   static void RemoveBacktrace(size_t hash_index);
 
   static void Add(const void* pointer, size_t size);
   static void Remove(const void* pointer);
 
-  typedef std::unordered_map<uintptr_t, PointerInfoType>::iterator iterator;
-  static iterator begin() { return pointers_.begin(); }
-  static iterator end() { return pointers_.end(); }
-
   static void* AddFreed(const void* pointer);
   static void LogFreeError(const FreePointerInfoType& info, size_t usable_size);
   static void LogFreeBacktrace(const void* ptr);
@@ -162,6 +161,12 @@
   static bool Exists(const void* pointer);
 
  private:
+  // Only keep mangled pointers in internal data structures. This avoids
+  // problems where libmemunreachable finds these pointers and thinks they
+  // are not unreachable.
+  static inline uintptr_t ManglePointer(uintptr_t pointer) { return pointer ^ UINTPTR_MAX; }
+  static inline uintptr_t DemanglePointer(uintptr_t pointer) { return pointer ^ UINTPTR_MAX; }
+
   static std::string GetHashString(uintptr_t* frames, size_t num_frames);
   static void LogBacktrace(size_t hash_index);
 
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 9f38946..d608f5d 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -890,10 +890,9 @@
                   void* arg) {
   ScopedConcurrentLock lock;
   if (g_debug->TrackPointers()) {
-    // Since malloc is disabled, don't bother acquiring any locks.
-    for (auto it = PointerData::begin(); it != PointerData::end(); ++it) {
-      callback(it->first, InternalMallocUsableSize(reinterpret_cast<void*>(it->first)), arg);
-    }
+    PointerData::IteratePointers([&callback, &arg](uintptr_t pointer) {
+      callback(pointer, InternalMallocUsableSize(reinterpret_cast<void*>(pointer)), arg);
+    });
     return 0;
   }