Refactor malloc debug.

Changes
- Refactor the code so that only guards require creating a special header
  for every pointer allocated.
- Store only a single copy of every backtrace. This saves memory so that
  turning on the backtrace option doesn't result in 10X memory usage.
- Added new option track_allocs that only verifies pointers are valid for
  free/malloc_usable_size/realloc.
- Remove suffix from test names.
- Add the TRACK_ALLOCS options to all guard options.
- Add new option verify_pointers that is a lightweight way to verify
  pointers that are passed to allocation routines.
- Do auto-formatting of the code.
- Updated documentation for all of these changes.

Bug: 74361929

Test: Ran unit tests.
Test: Ran libmemunreachable unit tests.
Test: Ran an app with backtrace enabled.

Change-Id: I3246c48ae4f9811f64622d90d0a9b4d9d818702c
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index ede2431..899987c 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -42,15 +42,13 @@
     name: "libc_malloc_debug",
 
     srcs: [
-        "BacktraceData.cpp",
         "Config.cpp",
         "DebugData.cpp",
         "debug_disable.cpp",
-        "FreeTrackData.cpp",
         "GuardData.cpp",
         "malloc_debug.cpp",
+        "PointerData.cpp",
         "RecordData.cpp",
-        "TrackData.cpp",
     ],
 
     stl: "libc++_static",
@@ -91,6 +89,7 @@
         "-Werror",
         "-fno-stack-protector",
         "-Wno-error=format-zero-length",
+        "-Wthread-safety",
     ],
 }
 
@@ -98,16 +97,7 @@
 // Unit Tests
 // ==============================================================
 cc_test {
-
     name: "malloc_debug_unit_tests",
-    multilib: {
-        lib32: {
-            suffix: "32",
-        },
-        lib64: {
-            suffix: "64",
-        },
-    },
 
     srcs: [
         "tests/backtrace_fake.cpp",
diff --git a/libc/malloc_debug/BacktraceData.cpp b/libc/malloc_debug/BacktraceData.cpp
deleted file mode 100644
index 57d8f2a..0000000
--- a/libc/malloc_debug/BacktraceData.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <private/bionic_macros.h>
-
-#include "BacktraceData.h"
-#include "Config.h"
-#include "DebugData.h"
-#include "debug_log.h"
-#include "malloc_debug.h"
-
-static void ToggleBacktraceEnable(int, siginfo_t*, void*) {
-  g_debug->backtrace->ToggleBacktraceEnabled();
-}
-
-static void EnableDump(int, siginfo_t*, void*) {
-  g_debug->backtrace->EnableDumping();
-}
-
-BacktraceData::BacktraceData(DebugData* debug_data, const Config& config, size_t* offset)
-    : OptionData(debug_data) {
-  size_t hdr_len = sizeof(BacktraceHeader) + sizeof(uintptr_t) * config.backtrace_frames();
-  alloc_offset_ = *offset;
-  *offset += __BIONIC_ALIGN(hdr_len, MINIMUM_ALIGNMENT_BYTES);
-}
-
-bool BacktraceData::Initialize(const Config& config) {
-  enabled_ = config.backtrace_enabled();
-  if (config.backtrace_enable_on_signal()) {
-    struct sigaction64 enable_act = {};
-    enable_act.sa_sigaction = ToggleBacktraceEnable;
-    enable_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
-    if (sigaction64(config.backtrace_signal(), &enable_act, nullptr) != 0) {
-      error_log("Unable to set up backtrace signal enable function: %s", strerror(errno));
-      return false;
-    }
-    info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
-             config.backtrace_signal(), getpid());
-  }
-
-  struct sigaction64 act = {};
-  act.sa_sigaction = EnableDump;
-  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
-  if (sigaction64(config.backtrace_dump_signal(), &act, nullptr) != 0) {
-    error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
-    return false;
-  }
-  info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
-           config.backtrace_dump_signal(), getpid());
-
-  dump_ = false;
-  return true;
-}
diff --git a/libc/malloc_debug/BacktraceData.h b/libc/malloc_debug/BacktraceData.h
deleted file mode 100644
index 3c15348..0000000
--- a/libc/malloc_debug/BacktraceData.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <stdint.h>
-
-#include <atomic>
-
-#include <private/bionic_macros.h>
-
-#include "OptionData.h"
-
-// Forward declarations.
-class Config;
-
-class BacktraceData : public OptionData {
- public:
-  BacktraceData(DebugData* debug_data, const Config& config, size_t* offset);
-  virtual ~BacktraceData() = default;
-
-  bool Initialize(const Config& config);
-
-  inline size_t alloc_offset() { return alloc_offset_; }
-
-  bool ShouldBacktrace() { return enabled_ == 1; }
-  void ToggleBacktraceEnabled() { enabled_.fetch_xor(1); }
-
-  void EnableDumping() { dump_ = true; }
-  bool ShouldDumpAndReset() {
-    bool expected = true;
-    return dump_.compare_exchange_strong(expected, false);
-  }
-
- private:
-  size_t alloc_offset_ = 0;
-
-  std::atomic_uint8_t enabled_;
-
-  std::atomic_bool dump_;
-
-  DISALLOW_COPY_AND_ASSIGN(BacktraceData);
-};
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index 3cecf9b..2c94fe8 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -69,65 +69,70 @@
 static constexpr const char DEFAULT_RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs.txt";
 
 const std::unordered_map<std::string, Config::OptionInfo> Config::kOptions = {
-    {"guard",
-      {FRONT_GUARD | REAR_GUARD, &Config::SetGuard},
+    {
+        "guard", {FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, &Config::SetGuard},
     },
-    {"front_guard",
-      {FRONT_GUARD, &Config::SetFrontGuard},
+    {
+        "front_guard", {FRONT_GUARD | TRACK_ALLOCS, &Config::SetFrontGuard},
     },
-    {"rear_guard",
-      {REAR_GUARD, &Config::SetRearGuard},
+    {
+        "rear_guard", {REAR_GUARD | TRACK_ALLOCS, &Config::SetRearGuard},
     },
 
-    {"backtrace",
-      {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
+    {
+        "backtrace", {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
     },
-    {"backtrace_enable_on_signal",
-      {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
+    {
+        "backtrace_enable_on_signal",
+        {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
     },
 
-    {"backtrace_dump_on_exit",
-      {0, &Config::SetBacktraceDumpOnExit},
+    {
+        "backtrace_dump_on_exit", {0, &Config::SetBacktraceDumpOnExit},
     },
-    {"backtrace_dump_prefix",
-      {0, &Config::SetBacktraceDumpPrefix},
+    {
+        "backtrace_dump_prefix", {0, &Config::SetBacktraceDumpPrefix},
     },
 
-    {"fill",
-      {FILL_ON_ALLOC | FILL_ON_FREE, &Config::SetFill},
+    {
+        "fill", {FILL_ON_ALLOC | FILL_ON_FREE, &Config::SetFill},
     },
-    {"fill_on_alloc",
-      {FILL_ON_ALLOC, &Config::SetFillOnAlloc},
+    {
+        "fill_on_alloc", {FILL_ON_ALLOC, &Config::SetFillOnAlloc},
     },
-    {"fill_on_free",
-      {FILL_ON_FREE, &Config::SetFillOnFree},
+    {
+        "fill_on_free", {FILL_ON_FREE, &Config::SetFillOnFree},
     },
 
-    {"expand_alloc",
-      {EXPAND_ALLOC, &Config::SetExpandAlloc},
+    {
+        "expand_alloc", {EXPAND_ALLOC, &Config::SetExpandAlloc},
     },
 
-    {"free_track",
-      {FREE_TRACK | FILL_ON_FREE, &Config::SetFreeTrack},
+    {
+        "free_track", {FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, &Config::SetFreeTrack},
     },
-    {"free_track_backtrace_num_frames",
-      {0, &Config::SetFreeTrackBacktraceNumFrames},
+    {
+        "free_track_backtrace_num_frames", {0, &Config::SetFreeTrackBacktraceNumFrames},
     },
 
-    {"leak_track",
-      {LEAK_TRACK | TRACK_ALLOCS, &Config::VerifyValueEmpty},
+    {
+        "leak_track", {LEAK_TRACK | TRACK_ALLOCS, &Config::VerifyValueEmpty},
     },
 
-    {"record_allocs",
-      {RECORD_ALLOCS, &Config::SetRecordAllocs},
+    {
+        "record_allocs", {RECORD_ALLOCS, &Config::SetRecordAllocs},
     },
-    {"record_allocs_file",
-      {0, &Config::SetRecordAllocsFile},
+    {
+        "record_allocs_file", {0, &Config::SetRecordAllocsFile},
+    },
+
+    {
+        "verify_pointers", {TRACK_ALLOCS, &Config::VerifyValueEmpty},
     },
 };
 
-bool Config::ParseValue(const std::string& option, const std::string& value,
-                        size_t min_value, size_t max_value, size_t* parsed_value) const {
+bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
+                        size_t max_value, size_t* parsed_value) const {
   assert(!value.empty());
 
   // Parse the value into a size_t value.
@@ -135,8 +140,7 @@
   char* end;
   long long_value = strtol(value.c_str(), &end, 10);
   if (errno != 0) {
-    error_log("%s: bad value for option '%s': %s", getprogname(), option.c_str(),
-              strerror(errno));
+    error_log("%s: bad value for option '%s': %s", getprogname(), option.c_str(), strerror(errno));
     return false;
   }
   if (end == value.c_str()) {
@@ -144,24 +148,24 @@
     return false;
   }
   if (static_cast<size_t>(end - value.c_str()) != value.size()) {
-    error_log("%s: bad value for option '%s', non space found after option: %s",
-              getprogname(), option.c_str(), end);
+    error_log("%s: bad value for option '%s', non space found after option: %s", getprogname(),
+              option.c_str(), end);
     return false;
   }
   if (long_value < 0) {
-    error_log("%s: bad value for option '%s', value cannot be negative: %ld",
-              getprogname(), option.c_str(), long_value);
+    error_log("%s: bad value for option '%s', value cannot be negative: %ld", getprogname(),
+              option.c_str(), long_value);
     return false;
   }
 
   if (static_cast<size_t>(long_value) < min_value) {
-    error_log("%s: bad value for option '%s', value must be >= %zu: %ld",
-              getprogname(), option.c_str(), min_value, long_value);
+    error_log("%s: bad value for option '%s', value must be >= %zu: %ld", getprogname(),
+              option.c_str(), min_value, long_value);
     return false;
   }
   if (static_cast<size_t>(long_value) > max_value) {
-    error_log("%s: bad value for option '%s', value must be <= %zu: %ld",
-              getprogname(), option.c_str(), max_value, long_value);
+    error_log("%s: bad value for option '%s', value must be <= %zu: %ld", getprogname(),
+              option.c_str(), max_value, long_value);
     return false;
   }
   *parsed_value = static_cast<size_t>(long_value);
@@ -261,7 +265,6 @@
   return true;
 }
 
-
 bool Config::SetExpandAlloc(const std::string& option, const std::string& value) {
   return ParseValue(option, value, DEFAULT_EXPAND_BYTES, 1, MAX_EXPAND_BYTES, &expand_alloc_bytes_);
 }
@@ -305,14 +308,13 @@
 bool Config::VerifyValueEmpty(const std::string& option, const std::string& value) {
   if (!value.empty()) {
     // This is not valid.
-    error_log("%s: value set for option '%s' which does not take a value",
-              getprogname(), option.c_str());
+    error_log("%s: value set for option '%s' which does not take a value", getprogname(),
+              option.c_str());
     return false;
   }
   return true;
 }
 
-
 void Config::LogUsage() const {
   error_log("malloc debug options usage:");
   error_log("");
@@ -329,8 +331,8 @@
   error_log("  guard[=XX]");
   error_log("    Enables both a front guard and a rear guard on all allocations.");
   error_log("    If XX is set it sets the number of bytes in both guards.");
-  error_log("    The default is %zu bytes, the max bytes is %zu.",
-            DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
+  error_log("    The default is %zu bytes, the max bytes is %zu.", DEFAULT_GUARD_BYTES,
+            MAX_GUARD_BYTES);
   error_log("");
   error_log("  backtrace[=XX]");
   error_log("    Enable capturing the backtrace at the point of allocation.");
@@ -419,13 +421,16 @@
   error_log("    This option only has meaning if the record_allocs options has been specified.");
   error_log("    This is the name of the file to which recording information will be dumped.");
   error_log("    The default is %s.", DEFAULT_RECORD_ALLOCS_FILE);
+  error_log("");
+  error_log("  verify_pointers");
+  error_log("    A lightweight way to verify that free/malloc_usable_size/realloc");
+  error_log("    are passed valid pointers.");
 }
 
 bool Config::GetOption(const char** options_str, std::string* option, std::string* value) {
   const char* cur = *options_str;
   // Process each property name we can find.
-  while (isspace(*cur))
-    ++cur;
+  while (isspace(*cur)) ++cur;
 
   if (*cur == '\0') {
     *options_str = cur;
@@ -433,25 +438,21 @@
   }
 
   const char* start = cur;
-  while (!isspace(*cur) && *cur != '=' && *cur != '\0')
-    ++cur;
+  while (!isspace(*cur) && *cur != '=' && *cur != '\0') ++cur;
 
   *option = std::string(start, cur - start);
 
   // Skip any spaces after the name.
-  while (isspace(*cur))
-    ++cur;
+  while (isspace(*cur)) ++cur;
 
   value->clear();
   if (*cur == '=') {
     ++cur;
     // Skip the space after the equal.
-    while (isspace(*cur))
-      ++cur;
+    while (isspace(*cur)) ++cur;
 
     start = cur;
-    while (!isspace(*cur) && *cur != '\0')
-      ++cur;
+    while (!isspace(*cur) && *cur != '\0') ++cur;
 
     if (cur != start) {
       *value = std::string(start, cur - start);
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index a310e09..3bcef0b 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -53,7 +53,7 @@
 #endif
 
 // If one or more of these options is set, then a special header is needed.
-constexpr uint64_t HEADER_OPTIONS = FRONT_GUARD | REAR_GUARD | BACKTRACE | FREE_TRACK | LEAK_TRACK;
+constexpr uint64_t HEADER_OPTIONS = FRONT_GUARD | REAR_GUARD;
 
 class Config {
  public:
diff --git a/libc/malloc_debug/DebugData.cpp b/libc/malloc_debug/DebugData.cpp
index 76f8fbb..44c4a10 100644
--- a/libc/malloc_debug/DebugData.cpp
+++ b/libc/malloc_debug/DebugData.cpp
@@ -28,14 +28,12 @@
 
 #include <stdint.h>
 
-#include "BacktraceData.h"
 #include "Config.h"
 #include "DebugData.h"
-#include "debug_disable.h"
-#include "FreeTrackData.h"
 #include "GuardData.h"
+#include "PointerData.h"
+#include "debug_disable.h"
 #include "malloc_debug.h"
-#include "TrackData.h"
 
 bool DebugData::Initialize(const char* options) {
   if (!config_.Init(options)) {
@@ -44,18 +42,9 @@
 
   // Check to see if the options that require a header are enabled.
   if (config_.options() & HEADER_OPTIONS) {
-    need_header_ = true;
-
     // Initialize all of the static header offsets.
     pointer_offset_ = __BIONIC_ALIGN(sizeof(Header), MINIMUM_ALIGNMENT_BYTES);
 
-    if (config_.options() & BACKTRACE) {
-      backtrace.reset(new BacktraceData(this, config_, &pointer_offset_));
-      if (!backtrace->Initialize(config_)) {
-        return false;
-      }
-    }
-
     if (config_.options() & FRONT_GUARD) {
       front_guard.reset(new FrontGuardData(this, config_, &pointer_offset_));
     }
@@ -67,13 +56,12 @@
       rear_guard.reset(new RearGuardData(this, config_));
       extra_bytes_ += config_.rear_guard_bytes();
     }
+  }
 
-    if (config_.options() & FREE_TRACK) {
-      free_track.reset(new FreeTrackData(this, config_));
-    }
-
-    if (config_.options() & TRACK_ALLOCS) {
-      track.reset(new TrackData(this));
+  if (TrackPointers()) {
+    pointer.reset(new PointerData(this));
+    if (!pointer->Initialize(config_)) {
+      return false;
     }
   }
 
@@ -91,28 +79,19 @@
 }
 
 void DebugData::PrepareFork() {
-  if (track != nullptr) {
-    track->PrepareFork();
-  }
-  if (free_track != nullptr) {
-    free_track->PrepareFork();
+  if (pointer != nullptr) {
+    pointer->PrepareFork();
   }
 }
 
 void DebugData::PostForkParent() {
-  if (track != nullptr) {
-    track->PostForkParent();
-  }
-  if (free_track != nullptr) {
-    free_track->PostForkParent();
+  if (pointer != nullptr) {
+    pointer->PostForkParent();
   }
 }
 
 void DebugData::PostForkChild() {
-  if (track != nullptr) {
-    track->PostForkChild();
-  }
-  if (free_track != nullptr) {
-    free_track->PostForkChild();
+  if (pointer != nullptr) {
+    pointer->PostForkChild();
   }
 }
diff --git a/libc/malloc_debug/DebugData.h b/libc/malloc_debug/DebugData.h
index 9aece0b..f7cf8ab 100644
--- a/libc/malloc_debug/DebugData.h
+++ b/libc/malloc_debug/DebugData.h
@@ -35,13 +35,11 @@
 
 #include <private/bionic_macros.h>
 
-#include "BacktraceData.h"
 #include "Config.h"
-#include "FreeTrackData.h"
 #include "GuardData.h"
-#include "malloc_debug.h"
+#include "PointerData.h"
 #include "RecordData.h"
-#include "TrackData.h"
+#include "malloc_debug.h"
 
 class DebugData {
  public:
@@ -62,11 +60,6 @@
     return reinterpret_cast<Header*>(value - pointer_offset_);
   }
 
-  BacktraceHeader* GetAllocBacktrace(const Header* header) {
-    uintptr_t value = reinterpret_cast<uintptr_t>(header);
-    return reinterpret_cast<BacktraceHeader*>(value + backtrace->alloc_offset());
-  }
-
   uint8_t* GetFrontGuard(const Header* header) {
     uintptr_t value = reinterpret_cast<uintptr_t>(header);
     return reinterpret_cast<uint8_t*>(value + front_guard->offset());
@@ -74,30 +67,30 @@
 
   uint8_t* GetRearGuard(const Header* header) {
     uintptr_t value = reinterpret_cast<uintptr_t>(GetPointer(header));
-    return reinterpret_cast<uint8_t*>(value + header->real_size());
+    return reinterpret_cast<uint8_t*>(value + header->size);
   }
 
   const Config& config() { return config_; }
   size_t pointer_offset() { return pointer_offset_; }
-  bool need_header() { return need_header_; }
   size_t extra_bytes() { return extra_bytes_; }
 
+  bool TrackPointers() { return config_.options() & TRACK_ALLOCS; }
+
+  bool HeaderEnabled() { return config_.options() & HEADER_OPTIONS; }
+
   void PrepareFork();
   void PostForkParent();
   void PostForkChild();
 
-  std::unique_ptr<BacktraceData> backtrace;
-  std::unique_ptr<TrackData> track;
   std::unique_ptr<FrontGuardData> front_guard;
+  std::unique_ptr<PointerData> pointer;
   std::unique_ptr<RearGuardData> rear_guard;
-  std::unique_ptr<FreeTrackData> free_track;
   std::unique_ptr<RecordData> record;
 
  private:
   size_t extra_bytes_ = 0;
 
   size_t pointer_offset_ = 0;
-  bool need_header_ = false;
 
   Config config_;
 
diff --git a/libc/malloc_debug/FreeTrackData.cpp b/libc/malloc_debug/FreeTrackData.cpp
deleted file mode 100644
index e8e7a67..0000000
--- a/libc/malloc_debug/FreeTrackData.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdint.h>
-
-#include "backtrace.h"
-#include "Config.h"
-#include "DebugData.h"
-#include "debug_disable.h"
-#include "debug_log.h"
-#include "FreeTrackData.h"
-#include "malloc_debug.h"
-
-FreeTrackData::FreeTrackData(DebugData* debug, const Config& config)
-    : OptionData(debug), backtrace_num_frames_(config.free_track_backtrace_num_frames()) {
-  cmp_mem_.resize(4096);
-  memset(cmp_mem_.data(), config.fill_free_value(), cmp_mem_.size());
-}
-
-void FreeTrackData::LogFreeError(const Header* header, const uint8_t* pointer) {
-  error_log(LOG_DIVIDER);
-  error_log("+++ ALLOCATION %p USED AFTER FREE", pointer);
-  uint8_t fill_free_value = debug_->config().fill_free_value();
-  for (size_t i = 0; i < header->usable_size; i++) {
-    if (pointer[i] != fill_free_value) {
-      error_log("  allocation[%zu] = 0x%02x (expected 0x%02x)", i, pointer[i], fill_free_value);
-    }
-  }
-  auto back_iter = backtraces_.find(header);
-  if (back_iter != backtraces_.end()) {
-    const BacktraceHeader* back_header = back_iter->second;
-    error_log("Backtrace at time of free:");
-    backtrace_log(&back_header->frames[0], back_header->num_frames);
-  }
-  error_log(LOG_DIVIDER);
-}
-
-void FreeTrackData::VerifyAndFree(const Header* header) {
-  const void* pointer = debug_->GetPointer(header);
-  if (header->tag != DEBUG_FREE_TAG) {
-    error_log(LOG_DIVIDER);
-    error_log("+++ ALLOCATION %p HAS CORRUPTED HEADER TAG 0x%x AFTER FREE", pointer, header->tag);
-    error_log(LOG_DIVIDER);
-  } else {
-    const uint8_t* memory = reinterpret_cast<const uint8_t*>(pointer);
-    size_t bytes = header->usable_size;
-    bytes = (bytes < debug_->config().fill_on_free_bytes()) ? bytes
-        : debug_->config().fill_on_free_bytes();
-    while (bytes > 0) {
-      size_t bytes_to_cmp = (bytes < cmp_mem_.size()) ? bytes : cmp_mem_.size();
-      if (memcmp(memory, cmp_mem_.data(), bytes_to_cmp) != 0) {
-        LogFreeError(header, reinterpret_cast<const uint8_t*>(pointer));
-        break;
-      }
-      bytes -= bytes_to_cmp;
-      memory = &memory[bytes_to_cmp];
-    }
-  }
-
-  auto back_iter = backtraces_.find(header);
-  if (back_iter != backtraces_.end()) {
-    g_dispatch->free(reinterpret_cast<void*>(back_iter->second));
-    backtraces_.erase(header);
-  }
-  g_dispatch->free(header->orig_pointer);
-}
-
-void FreeTrackData::Add(const Header* header) {
-  pthread_mutex_lock(&mutex_);
-  if (list_.size() == debug_->config().free_track_allocations()) {
-    const Header* old_header = list_.back();
-    VerifyAndFree(old_header);
-    list_.pop_back();
-  }
-
-  if (backtrace_num_frames_ > 0) {
-    BacktraceHeader* back_header = reinterpret_cast<BacktraceHeader*>(
-      g_dispatch->malloc(sizeof(BacktraceHeader) + backtrace_num_frames_ * sizeof(uintptr_t)));
-    if (back_header) {
-      back_header->num_frames = backtrace_get(&back_header->frames[0], backtrace_num_frames_);
-      backtraces_[header] = back_header;
-    }
-  }
-  list_.push_front(header);
-
-  pthread_mutex_unlock(&mutex_);
-}
-
-void FreeTrackData::VerifyAll() {
-  for (const auto& header : list_) {
-    VerifyAndFree(header);
-  }
-  list_.clear();
-}
-
-void FreeTrackData::LogBacktrace(const Header* header) {
-  auto back_iter = backtraces_.find(header);
-  if (back_iter == backtraces_.end()) {
-    return;
-  }
-
-  error_log("Backtrace of original free:");
-  backtrace_log(&back_iter->second->frames[0], back_iter->second->num_frames);
-}
diff --git a/libc/malloc_debug/FreeTrackData.h b/libc/malloc_debug/FreeTrackData.h
deleted file mode 100644
index bd3497d..0000000
--- a/libc/malloc_debug/FreeTrackData.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <pthread.h>
-
-#include <deque>
-#include <unordered_map>
-#include <vector>
-
-#include <private/bionic_macros.h>
-
-#include "OptionData.h"
-
-// Forward declarations.
-struct BacktraceHeader;
-class Config;
-class DebugData;
-struct Header;
-
-class FreeTrackData : public OptionData {
- public:
-  FreeTrackData(DebugData* debug_data, const Config& config);
-  virtual ~FreeTrackData() = default;
-
-  void Add(const Header* header);
-
-  void VerifyAll();
-
-  void LogBacktrace(const Header* header);
-
-  void PrepareFork() { pthread_mutex_lock(&mutex_); }
-
-  void PostForkParent() { pthread_mutex_unlock(&mutex_); }
-
-  void PostForkChild() { pthread_mutex_init(&mutex_, NULL); }
-
- private:
-  void LogFreeError(const Header* header, const uint8_t* pointer);
-  void VerifyAndFree(const Header* header);
-
-  pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
-  std::deque<const Header*> list_;
-  std::vector<uint8_t> cmp_mem_;
-  std::unordered_map<const Header*, BacktraceHeader*> backtraces_;
-  size_t backtrace_num_frames_;
-
-  DISALLOW_COPY_AND_ASSIGN(FreeTrackData);
-};
diff --git a/libc/malloc_debug/GuardData.cpp b/libc/malloc_debug/GuardData.cpp
index d6cef85..f9a2dca 100644
--- a/libc/malloc_debug/GuardData.cpp
+++ b/libc/malloc_debug/GuardData.cpp
@@ -31,13 +31,13 @@
 
 #include <vector>
 
-#include "backtrace.h"
 #include "Config.h"
+#include "DebugData.h"
+#include "GuardData.h"
+#include "backtrace.h"
 #include "debug_disable.h"
 #include "debug_log.h"
-#include "DebugData.h"
 #include "malloc_debug.h"
-#include "GuardData.h"
 
 GuardData::GuardData(DebugData* debug_data, int init_value, size_t num_bytes)
     : OptionData(debug_data) {
@@ -48,8 +48,8 @@
 
 void GuardData::LogFailure(const Header* header, const void* pointer, const void* data) {
   error_log(LOG_DIVIDER);
-  error_log("+++ ALLOCATION %p SIZE %zu HAS A CORRUPTED %s GUARD", pointer,
-            header->real_size(), GetTypeName());
+  error_log("+++ ALLOCATION %p SIZE %zu HAS A CORRUPTED %s GUARD", pointer, header->size,
+            GetTypeName());
 
   // Log all of the failing bytes.
   const uint8_t* expected = cmp_mem_.data();
@@ -70,7 +70,7 @@
 }
 
 FrontGuardData::FrontGuardData(DebugData* debug_data, const Config& config, size_t* offset)
-   : GuardData(debug_data, config.front_guard_value(), config.front_guard_bytes()) {
+    : GuardData(debug_data, config.front_guard_value(), config.front_guard_bytes()) {
   // Create a buffer for fast comparisons of the front guard.
   cmp_mem_.resize(config.front_guard_bytes());
   memset(cmp_mem_.data(), config.front_guard_value(), cmp_mem_.size());
@@ -88,8 +88,7 @@
 }
 
 RearGuardData::RearGuardData(DebugData* debug_data, const Config& config)
-    : GuardData(debug_data, config.rear_guard_value(), config.rear_guard_bytes()) {
-}
+    : GuardData(debug_data, config.rear_guard_value(), config.rear_guard_bytes()) {}
 
 bool RearGuardData::Valid(const Header* header) {
   return GuardData::Valid(debug_->GetRearGuard(header));
diff --git a/libc/malloc_debug/MapData.cpp b/libc/malloc_debug/MapData.cpp
index d57017e..060425e 100644
--- a/libc/malloc_debug/MapData.cpp
+++ b/libc/malloc_debug/MapData.cpp
@@ -31,8 +31,8 @@
 #include <inttypes.h>
 #include <link.h>
 #include <stdio.h>
-#include <string.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <vector>
 
@@ -46,8 +46,8 @@
   uintptr_t offset;
   char permissions[5];
   int name_pos;
-  if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start,
-             &end, permissions, &offset, &name_pos) < 2) {
+  if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d %n", &start, &end,
+             permissions, &offset, &name_pos) < 2) {
     return nullptr;
   }
 
@@ -66,13 +66,13 @@
   return entry;
 }
 
-template<typename T>
+template <typename T>
 static inline bool get_val(MapEntry* entry, uintptr_t addr, T* store) {
   if (addr < entry->start || addr + sizeof(T) > entry->end) {
     return false;
   }
   // Make sure the address is aligned properly.
-  if (addr & (sizeof(T)-1)) {
+  if (addr & (sizeof(T) - 1)) {
     return false;
   }
   *store = *reinterpret_cast<T*>(addr);
@@ -157,7 +157,7 @@
     return nullptr;
   }
 
-  MapEntry *entry = *it;
+  MapEntry* entry = *it;
   if (!entry->load_base_read) {
     read_loadbase(entry);
   }
diff --git a/libc/malloc_debug/MapData.h b/libc/malloc_debug/MapData.h
index a71f96d..d8398bd 100644
--- a/libc/malloc_debug/MapData.h
+++ b/libc/malloc_debug/MapData.h
@@ -31,8 +31,8 @@
 #include <sys/cdefs.h>
 
 #include <mutex>
-#include <string>
 #include <set>
+#include <string>
 
 #include <private/bionic_macros.h>
 
@@ -50,12 +50,9 @@
   std::string name;
 };
 
-
 // Ordering comparator that returns equivalence for overlapping entries
 struct compare_entries {
-  bool operator()(const MapEntry* a, const MapEntry* b) const {
-    return a->end <= b->start;
-  }
+  bool operator()(const MapEntry* a, const MapEntry* b) const { return a->end <= b->start; }
 };
 
 class MapData {
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
new file mode 100644
index 0000000..f811a5e
--- /dev/null
+++ b/libc/malloc_debug/PointerData.cpp
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
+#include <private/bionic_macros.h>
+
+#include "Config.h"
+#include "DebugData.h"
+#include "PointerData.h"
+#include "backtrace.h"
+#include "debug_log.h"
+#include "malloc_debug.h"
+
+std::atomic_uint8_t PointerData::backtrace_enabled_;
+std::atomic_bool PointerData::backtrace_dump_;
+
+std::mutex PointerData::pointer_mutex_;
+std::unordered_map<uintptr_t, PointerInfoType> PointerData::pointers_ GUARDED_BY(
+    PointerData::pointer_mutex_);
+
+std::mutex PointerData::frame_mutex_;
+std::unordered_map<FrameKeyType, size_t> PointerData::key_to_index_ GUARDED_BY(
+    PointerData::frame_mutex_);
+std::unordered_map<size_t, FrameInfoType> PointerData::frames_ GUARDED_BY(PointerData::frame_mutex_);
+constexpr size_t kBacktraceEmptyIndex = 1;
+size_t PointerData::cur_hash_index_ GUARDED_BY(PointerData::frame_mutex_);
+
+std::mutex PointerData::free_pointer_mutex_;
+std::deque<FreePointerInfoType> PointerData::free_pointers_ GUARDED_BY(
+    PointerData::free_pointer_mutex_);
+
+// Buffer to use for comparison.
+static constexpr size_t kCompareBufferSize = 512 * 1024;
+static std::vector<uint8_t> g_cmp_mem(0);
+
+static void ToggleBacktraceEnable(int, siginfo_t*, void*) {
+  g_debug->pointer->ToggleBacktraceEnabled();
+}
+
+static void EnableDump(int, siginfo_t*, void*) {
+  g_debug->pointer->EnableDumping();
+}
+
+PointerData::PointerData(DebugData* debug_data) : OptionData(debug_data) {}
+
+bool PointerData::Initialize(const Config& config) NO_THREAD_SAFETY_ANALYSIS {
+  pointers_.clear();
+  key_to_index_.clear();
+  frames_.clear();
+  free_pointers_.clear();
+  // A hash index of kBacktraceEmptyIndex indicates that we tried to get
+  // a backtrace, but there was nothing recorded.
+  cur_hash_index_ = kBacktraceEmptyIndex + 1;
+
+  backtrace_enabled_ = config.backtrace_enabled();
+  if (config.backtrace_enable_on_signal()) {
+    struct sigaction64 enable_act = {};
+    enable_act.sa_sigaction = ToggleBacktraceEnable;
+    enable_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+    if (sigaction64(config.backtrace_signal(), &enable_act, nullptr) != 0) {
+      error_log("Unable to set up backtrace signal enable function: %s", strerror(errno));
+      return false;
+    }
+    info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
+             config.backtrace_signal(), getpid());
+  }
+
+  if (config.options() & BACKTRACE) {
+    struct sigaction64 act = {};
+    act.sa_sigaction = EnableDump;
+    act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+    if (sigaction64(config.backtrace_dump_signal(), &act, nullptr) != 0) {
+      error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
+      return false;
+    }
+    info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
+             config.backtrace_dump_signal(), getpid());
+  }
+
+  backtrace_dump_ = false;
+
+  if (config.options() & FREE_TRACK) {
+    g_cmp_mem.resize(kCompareBufferSize, config.fill_free_value());
+  }
+  return true;
+}
+
+size_t PointerData::AddBacktrace(size_t num_frames) {
+  std::vector<uintptr_t> frames(num_frames);
+  num_frames = backtrace_get(frames.data(), frames.size());
+  if (num_frames == 0) {
+    return kBacktraceEmptyIndex;
+  }
+
+  FrameKeyType key{.num_frames = num_frames, .frames = frames.data()};
+  size_t hash_index;
+  std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+  auto entry = key_to_index_.find(key);
+  if (entry == key_to_index_.end()) {
+    frames.resize(num_frames);
+    hash_index = cur_hash_index_++;
+    key.frames = frames.data();
+    key_to_index_.emplace(key, hash_index);
+
+    frames_.emplace(hash_index, FrameInfoType{.references = 1, .frames = std::move(frames)});
+  } else {
+    hash_index = entry->second;
+    FrameInfoType* frame_info = &frames_[hash_index];
+    frame_info->references++;
+  }
+  return hash_index;
+}
+
+void PointerData::RemoveBacktrace(size_t hash_index) {
+  if (hash_index <= kBacktraceEmptyIndex) {
+    return;
+  }
+
+  std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+  auto frame_entry = frames_.find(hash_index);
+  if (frame_entry == frames_.end()) {
+    error_log("hash_index %zu does not have matching frame data.", hash_index);
+    return;
+  }
+  FrameInfoType* frame_info = &frame_entry->second;
+  if (--frame_info->references == 0) {
+    FrameKeyType key{.num_frames = frame_info->frames.size(), .frames = frame_info->frames.data()};
+    key_to_index_.erase(key);
+    frames_.erase(hash_index);
+  }
+}
+
+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};
+}
+
+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);
+    if (entry == pointers_.end()) {
+      // Error.
+      error_log("No tracked pointer found for 0x%" PRIxPTR, pointer);
+      return;
+    }
+    hash_index = entry->second.hash_index;
+    pointers_.erase(pointer);
+  }
+
+  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);
+    if (entry == pointers_.end()) {
+      return 0;
+    }
+    hash_index = entry->second.hash_index;
+  }
+
+  if (hash_index <= kBacktraceEmptyIndex) {
+    return 0;
+  }
+
+  std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+  auto frame_entry = frames_.find(hash_index);
+  if (frame_entry == frames_.end()) {
+    return 0;
+  }
+  FrameInfoType* frame_info = &frame_entry->second;
+  if (max_frames > frame_info->frames.size()) {
+    max_frames = frame_info->frames.size();
+  }
+  memcpy(frames, &frame_info->frames[0], max_frames * sizeof(uintptr_t));
+
+  return max_frames;
+}
+
+void PointerData::LogFreeError(const FreePointerInfoType& info, size_t usable_size) {
+  error_log(LOG_DIVIDER);
+  uint8_t* memory = reinterpret_cast<uint8_t*>(info.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 < usable_size; i++) {
+    if (memory[i] != fill_free_value) {
+      error_log("  allocation[%zu] = 0x%02x (expected 0x%02x)", i, memory[i], fill_free_value);
+    }
+  }
+
+  if (info.hash_index > kBacktraceEmptyIndex) {
+    std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+    auto frame_entry = frames_.find(info.hash_index);
+    if (frame_entry != frames_.end()) {
+      FrameInfoType* frame_info = &frame_entry->second;
+      error_log("Backtrace at time of free:");
+      backtrace_log(frame_info->frames.data(), frame_info->frames.size());
+    }
+  }
+
+  error_log(LOG_DIVIDER);
+}
+
+void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
+  size_t usable_size;
+  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));
+    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(LOG_DIVIDER);
+
+      // Stop processing here, it is impossible to tell how the header
+      // may have been damaged.
+      return;
+    }
+    usable_size = header->usable_size;
+  } else {
+    usable_size = g_dispatch->malloc_usable_size(reinterpret_cast<const void*>(info.pointer));
+  }
+
+  size_t bytes = (usable_size < g_debug->config().fill_on_free_bytes())
+                     ? usable_size
+                     : g_debug->config().fill_on_free_bytes();
+  const uint8_t* memory = reinterpret_cast<const uint8_t*>(info.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) {
+      LogFreeError(info, usable_size);
+    }
+    bytes -= bytes_to_cmp;
+    memory = &memory[bytes_to_cmp];
+  }
+}
+
+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) {
+    hash_index = AddBacktrace(num_frames);
+  }
+
+  void* last = nullptr;
+  std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
+  if (free_pointers_.size() == g_debug->config().free_track_allocations()) {
+    FreePointerInfoType info(free_pointers_.front());
+    free_pointers_.pop_front();
+    VerifyFreedPointer(info);
+    RemoveBacktrace(info.hash_index);
+    last = reinterpret_cast<void*>(info.pointer);
+  }
+
+  free_pointers_.emplace_back(FreePointerInfoType{pointer, hash_index});
+  return last;
+}
+
+void PointerData::LogFreeBacktrace(const void* ptr) {
+  size_t hash_index = 0;
+  {
+    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) {
+        hash_index = info.hash_index;
+        break;
+      }
+    }
+  }
+
+  if (hash_index <= kBacktraceEmptyIndex) {
+    return;
+  }
+
+  std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+  auto frame_entry = frames_.find(hash_index);
+  if (frame_entry == frames_.end()) {
+    error_log("Freed pointer hash_index %zu does not have matching frame data.", hash_index);
+    return;
+  }
+  FrameInfoType* frame_info = &frame_entry->second;
+  error_log("Backtrace of original free:");
+  backtrace_log(frame_info->frames.data(), frame_info->frames.size());
+}
+
+void PointerData::VerifyAllFreed() {
+  std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
+  for (auto& free_info : free_pointers_) {
+    VerifyFreedPointer(free_info);
+  }
+}
+
+void PointerData::GetList(std::vector<ListInfoType>* list, bool only_with_backtrace)
+    REQUIRES(pointer_mutex_, frame_mutex_) {
+  for (const auto& entry : pointers_) {
+    FrameInfoType* frame_info = nullptr;
+    size_t hash_index = entry.second.hash_index;
+    if (hash_index > kBacktraceEmptyIndex) {
+      frame_info = &frames_[hash_index];
+      if (frame_info->references == 0) {
+        // Somehow wound up with a pointer with a valid hash_index, but
+        // no frame data. This should not be possible since adding a pointer
+        // occurs after the hash_index and frame data have been added.
+        // When removing a pointer, the pointer is deleted before the frame
+        // data.
+        frames_.erase(hash_index);
+        error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
+        frame_info = nullptr;
+      }
+    }
+    if (hash_index == 0 && only_with_backtrace) {
+      continue;
+    }
+
+    list->emplace_back(ListInfoType{entry.first, 1, entry.second.RealSize(),
+                                    entry.second.ZygoteChildAlloc(), frame_info});
+  }
+
+  // Sort by the size of the allocation.
+  std::sort(list->begin(), list->end(), [](const ListInfoType& a, const ListInfoType& b) {
+    // Put zygote child allocations first.
+    bool a_zygote_child_alloc = a.zygote_child_alloc;
+    bool b_zygote_child_alloc = b.zygote_child_alloc;
+    if (a_zygote_child_alloc && !b_zygote_child_alloc) {
+      return false;
+    }
+    if (!a_zygote_child_alloc && b_zygote_child_alloc) {
+      return true;
+    }
+
+    // Sort by size, descending order.
+    if (a.size != b.size) return a.size > b.size;
+
+    // Put pointers with no backtrace last.
+    FrameInfoType* a_frame = a.frame_info;
+    FrameInfoType* b_frame = b.frame_info;
+    if (a_frame == nullptr && b_frame != nullptr) {
+      return false;
+    }
+    if (a_frame != nullptr && b_frame == nullptr) {
+      return true;
+    }
+    // Put the pointers with longest backtrace first.
+    if (a_frame->frames.size() != b_frame->frames.size()) {
+      return a_frame->frames.size() > b_frame->frames.size();
+    }
+
+    // Last sort by pointer.
+    return a.pointer < b.pointer;
+  });
+}
+
+void PointerData::GetUniqueList(std::vector<ListInfoType>* list, bool only_with_backtrace)
+    REQUIRES(pointer_mutex_, frame_mutex_) {
+  GetList(list, only_with_backtrace);
+
+  // Remove duplicates of size/backtraces.
+  for (auto iter = list->begin(); iter != list->end();) {
+    auto dup_iter = iter + 1;
+    bool zygote_child_alloc = iter->zygote_child_alloc;
+    size_t size = iter->size;
+    FrameInfoType* frame_info = iter->frame_info;
+    for (; dup_iter != list->end(); ++dup_iter) {
+      if (zygote_child_alloc != dup_iter->zygote_child_alloc || size != dup_iter->size ||
+          frame_info != dup_iter->frame_info) {
+        break;
+      }
+      iter->num_allocations++;
+    }
+    iter = list->erase(iter + 1, dup_iter);
+  }
+}
+
+void PointerData::LogLeaks() {
+  std::vector<ListInfoType> list;
+
+  std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+  std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+  GetList(&list, false);
+
+  size_t track_count = 0;
+  for (const auto& list_info : list) {
+    error_log("+++ %s leaked block of size %zu at 0x%" PRIxPTR " (leak %zu of %zu)", getprogname(),
+              list_info.size, list_info.pointer, ++track_count, list.size());
+    if (list_info.frame_info != nullptr) {
+      error_log("Backtrace at time of allocation:");
+      backtrace_log(list_info.frame_info->frames.data(), list_info.frame_info->frames.size());
+    }
+    // Do not bother to free the pointers, we are about to exit any way.
+  }
+}
+
+void PointerData::GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
+                          size_t* total_memory, size_t* backtrace_size) {
+  std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+  std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+
+  if (pointers_.empty()) {
+    return;
+  }
+
+  std::vector<ListInfoType> list;
+  GetUniqueList(&list, true);
+  if (list.empty()) {
+    return;
+  }
+
+  *backtrace_size = g_debug->config().backtrace_frames();
+  *info_size = sizeof(size_t) * 2 + sizeof(uintptr_t) * *backtrace_size;
+  *overall_size = *info_size * list.size();
+  *info = reinterpret_cast<uint8_t*>(g_dispatch->calloc(*info_size, list.size()));
+  if (*info == nullptr) {
+    return;
+  }
+
+  uint8_t* data = *info;
+  *total_memory = 0;
+  for (const auto& list_info : list) {
+    FrameInfoType* frame_info = list_info.frame_info;
+    *total_memory += list_info.size * list_info.num_allocations;
+    size_t allocation_size =
+        PointerInfoType::GetEncodedSize(list_info.zygote_child_alloc, list_info.size);
+    memcpy(data, &allocation_size, sizeof(size_t));
+    memcpy(&data[sizeof(size_t)], &list_info.num_allocations, sizeof(size_t));
+    if (frame_info != nullptr) {
+      memcpy(&data[2 * sizeof(size_t)], frame_info->frames.data(),
+             frame_info->frames.size() * sizeof(uintptr_t));
+    }
+    data += *info_size;
+  }
+}
+
+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;
+}
+
+void PointerData::DumpLiveToFile(FILE* fp) {
+  std::vector<ListInfoType> list;
+
+  std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+  std::lock_guard<std::mutex> frame_guard(frame_mutex_);
+  GetUniqueList(&list, false);
+
+  size_t total_memory = 0;
+  for (const auto& info : list) {
+    total_memory += info.size * info.num_allocations;
+  }
+
+  fprintf(fp, "Total memory: %zu\n", total_memory);
+  fprintf(fp, "Allocation records: %zd\n", list.size());
+  fprintf(fp, "Backtrace size: %zu\n", g_debug->config().backtrace_frames());
+  fprintf(fp, "\n");
+
+  for (const auto& info : list) {
+    fprintf(fp, "z %d  sz %8zu  num    %zu  bt", (info.zygote_child_alloc) ? 1 : 0, info.size,
+            info.num_allocations);
+    FrameInfoType* frame_info = info.frame_info;
+    if (frame_info != nullptr) {
+      for (size_t i = 0; i < frame_info->frames.size(); i++) {
+        if (frame_info->frames[i] == 0) {
+          break;
+        }
+#if defined(__LP64__)
+        fprintf(fp, " %016" PRIxPTR, frame_info->frames[i]);
+#else
+        fprintf(fp, " %08" PRIxPTR, frame_info->frames[i]);
+#endif
+      }
+    }
+    fprintf(fp, "\n");
+  }
+}
+
+void PointerData::PrepareFork() NO_THREAD_SAFETY_ANALYSIS {
+  pointer_mutex_.lock();
+  frame_mutex_.lock();
+  free_pointer_mutex_.lock();
+}
+
+void PointerData::PostForkParent() NO_THREAD_SAFETY_ANALYSIS {
+  frame_mutex_.unlock();
+  pointer_mutex_.unlock();
+  free_pointer_mutex_.unlock();
+}
+
+void PointerData::PostForkChild() __attribute__((no_thread_safety_analysis)) {
+  // Make sure that any potential mutexes have been released and are back
+  // to an initial state.
+  frame_mutex_.try_lock();
+  frame_mutex_.unlock();
+  pointer_mutex_.try_lock();
+  pointer_mutex_.unlock();
+  free_pointer_mutex_.try_lock();
+  free_pointer_mutex_.unlock();
+}
diff --git a/libc/malloc_debug/PointerData.h b/libc/malloc_debug/PointerData.h
new file mode 100644
index 0000000..7a0b3b8
--- /dev/null
+++ b/libc/malloc_debug/PointerData.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <atomic>
+#include <deque>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <private/bionic_macros.h>
+
+#include "OptionData.h"
+
+extern int* g_malloc_zygote_child;
+
+// Forward declarations.
+class Config;
+
+struct FrameKeyType {
+  size_t num_frames;
+  uintptr_t* frames;
+
+  bool operator==(const FrameKeyType& comp) const {
+    if (num_frames != comp.num_frames) return false;
+    for (size_t i = 0; i < num_frames; i++) {
+      if (frames[i] != comp.frames[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+};
+
+namespace std {
+template <>
+struct hash<FrameKeyType> {
+  std::size_t operator()(const FrameKeyType& key) const {
+    std::size_t cur_hash = key.frames[0];
+    // Limit the number of frames to speed up hashing.
+    size_t max_frames = (key.num_frames > 5) ? 5 : key.num_frames;
+    for (size_t i = 1; i < max_frames; i++) {
+      cur_hash ^= key.frames[i];
+    }
+    return cur_hash;
+  }
+};
+};  // namespace std
+
+struct FrameInfoType {
+  size_t references = 0;
+  std::vector<uintptr_t> frames;
+};
+
+struct PointerInfoType {
+  size_t size;
+  size_t hash_index;
+  size_t RealSize() const { return size & ~(1U << 31); }
+  bool ZygoteChildAlloc() const { return size & (1U << 31); }
+  static size_t GetEncodedSize(size_t size) { return GetEncodedSize(*g_malloc_zygote_child, size); }
+  static size_t GetEncodedSize(bool child_alloc, size_t size) {
+    return size | ((child_alloc) ? (1U << 31) : 0);
+  }
+  static size_t MaxSize() { return (1U << 31) - 1; }
+};
+
+struct FreePointerInfoType {
+  uintptr_t pointer;
+  size_t hash_index;
+};
+
+struct ListInfoType {
+  uintptr_t pointer;
+  size_t num_allocations;
+  size_t size;
+  bool zygote_child_alloc;
+  FrameInfoType* frame_info;
+};
+
+class PointerData : public OptionData {
+ public:
+  PointerData(DebugData* debug_data);
+  virtual ~PointerData() = default;
+
+  bool Initialize(const Config& config);
+
+  inline size_t alloc_offset() { return alloc_offset_; }
+
+  bool ShouldBacktrace() { return backtrace_enabled_ == 1; }
+  void ToggleBacktraceEnabled() { backtrace_enabled_.fetch_xor(1); }
+
+  void EnableDumping() { backtrace_dump_ = true; }
+  bool ShouldDumpAndReset() {
+    bool expected = true;
+    return backtrace_dump_.compare_exchange_strong(expected, false);
+  }
+
+  void PrepareFork();
+  void PostForkParent();
+  void PostForkChild();
+
+  static void GetList(std::vector<ListInfoType>* list, bool only_with_backtrace);
+  static void GetUniqueList(std::vector<ListInfoType>* list, bool only_with_backtrace);
+
+  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);
+  static void VerifyFreedPointer(const FreePointerInfoType& info);
+  static void VerifyAllFreed();
+
+  static void LogLeaks();
+  static void DumpLiveToFile(FILE* fp);
+
+  static void GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory,
+                      size_t* backtrace_size);
+
+  static size_t GetFrames(const void* pointer, uintptr_t* frames, size_t max_frames);
+
+  static bool Exists(const void* pointer);
+
+ private:
+  static std::string GetHashString(uintptr_t* frames, size_t num_frames);
+
+  size_t alloc_offset_ = 0;
+  std::vector<uint8_t> cmp_mem_;
+
+  static std::atomic_uint8_t backtrace_enabled_;
+
+  static std::atomic_bool backtrace_dump_;
+
+  static std::mutex pointer_mutex_;
+  static std::unordered_map<uintptr_t, PointerInfoType> pointers_;
+
+  static std::mutex frame_mutex_;
+  static std::unordered_map<FrameKeyType, size_t> key_to_index_;
+  static std::unordered_map<size_t, FrameInfoType> frames_;
+  static size_t cur_hash_index_;
+
+  static std::mutex free_pointer_mutex_;
+  static std::deque<FreePointerInfoType> free_pointers_;
+
+  DISALLOW_COPY_AND_ASSIGN(PointerData);
+};
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index 69d0648..59ab6ad 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -33,6 +33,13 @@
 
 Any errors detected by the library are reported in the log.
 
+NOTE: There is a small behavioral change beginning in P for realloc.
+Before, a realloc from one size to a smaller size would not update the
+backtrace related to the allocation. Starting in P, every single realloc
+call changes the backtrace for the pointer no matter whether the pointer
+returned has changed or not.
+
+
 Controlling Malloc Debug Behavior
 ---------------------------------
 Malloc debug is controlled by individual options. Each option can be enabled
@@ -106,8 +113,9 @@
 capture in a backtrace. The default is 16 frames, the maximumum value
 this can be set to is 256.
 
-This option adds a special header to all allocations that contains the
-backtrace and information about the original allocation.
+Before P, this option adds a special header to all allocations that contains
+the backtrace and information about the original allocation. After that, this
+option will not add a special header.
 
 As of P, this option will also enable dumping backtrace heap data to a
 file when the process receives the signal SIGRTMAX - 17 ( which is 47 on most
@@ -132,8 +140,9 @@
 capture in a backtrace. The default is 16 frames, the maximumum value
 this can be set to is 256.
 
-This option adds a special header to all allocations that contains the
-backtrace and information about the original allocation.
+Before P, this option adds a special header to all allocations that contains
+the backtrace and information about the original allocation. After that, this
+option will not add a special header.
 
 ### backtrace\_dump\_on\_exit
 As of P, when the backtrace option has been enabled, this causes the backtrace
@@ -201,8 +210,9 @@
 in the list. The default is to record 100 freed allocations, the max
 allocations to record is 16384.
 
-This option adds a special header to all allocations that contains
-information about the original allocation.
+Before P, this option adds a special header to all allocations that contains
+the backtrace and information about the original allocation. After that, this
+option will not add a special header.
 
 Example error:
 
@@ -238,8 +248,9 @@
 option is not useful when enabled globally because a lot of programs do not
 free everything before the program terminates.
 
-This option adds a special header to all allocations that contains
-information about the original allocation.
+Before P, this option adds a special header to all allocations that contains
+the backtrace and information about the original allocation. After that, this
+option will not add a special header.
 
 Example leak error found in the log:
 
@@ -362,6 +373,26 @@
 
 **NOTE**: This option is not available until the O release of Android.
 
+### verify\_pointers
+Track all live allocations to determine if a pointer is used that does not
+exist. This option is a lightweight way to verify that all
+free/malloc\_usable\_size/realloc calls are passed valid pointers.
+
+Example error:
+
+    04-15 12:00:31.304  7412  7412 E malloc_debug: +++ ALLOCATION 0x12345678 UNKNOWN POINTER (free)
+    04-15 12:00:31.305  7412  7412 E malloc_debug: Backtrace at time of failure:
+    04-15 12:00:31.305  7412  7412 E malloc_debug:           #00  pc 00029310  /system/lib/libc.so
+    04-15 12:00:31.305  7412  7412 E malloc_debug:           #01  pc 00021438  /system/lib/libc.so (newlocale+160)
+    04-15 12:00:31.305  7412  7412 E malloc_debug:           #02  pc 000a9e38  /system/lib/libc++.so
+    04-15 12:00:31.305  7412  7412 E malloc_debug:           #03  pc 000a28a8  /system/lib/libc++.so
+
+Where the name of the function varies depending on the function that called
+with a bad pointer. Only three functions do this checking: free,
+malloc\_usable\_size, realloc.
+
+**NOTE**: This option is not available until the P release of Android.
+
 Additional Errors
 -----------------
 There are a few other error messages that might appear in the log.
diff --git a/libc/malloc_debug/RecordData.cpp b/libc/malloc_debug/RecordData.cpp
index 8e9c671..aea2513 100644
--- a/libc/malloc_debug/RecordData.cpp
+++ b/libc/malloc_debug/RecordData.cpp
@@ -40,10 +40,10 @@
 #include <android-base/stringprintf.h>
 
 #include "Config.h"
-#include "debug_disable.h"
-#include "debug_log.h"
 #include "DebugData.h"
 #include "RecordData.h"
+#include "debug_disable.h"
+#include "debug_log.h"
 
 RecordEntry::RecordEntry() : tid_(gettid()) {
 }
@@ -52,52 +52,45 @@
   return android::base::StringPrintf("%d: thread_done 0x0\n", tid_);
 }
 
-AllocEntry::AllocEntry(void* pointer) : pointer_(pointer) {
-}
+AllocEntry::AllocEntry(void* pointer) : pointer_(pointer) {}
 
-MallocEntry::MallocEntry(void* pointer, size_t size) : AllocEntry(pointer), size_(size) {
-}
+MallocEntry::MallocEntry(void* pointer, size_t size) : AllocEntry(pointer), size_(size) {}
 
 std::string MallocEntry::GetString() const {
   return android::base::StringPrintf("%d: malloc %p %zu\n", tid_, pointer_, size_);
 }
 
-FreeEntry::FreeEntry(void* pointer) : AllocEntry(pointer) {
-}
+FreeEntry::FreeEntry(void* pointer) : AllocEntry(pointer) {}
 
 std::string FreeEntry::GetString() const {
   return android::base::StringPrintf("%d: free %p\n", tid_, pointer_);
 }
 
 CallocEntry::CallocEntry(void* pointer, size_t nmemb, size_t size)
-    : MallocEntry(pointer, size), nmemb_(nmemb) {
-}
+    : MallocEntry(pointer, size), nmemb_(nmemb) {}
 
 std::string CallocEntry::GetString() const {
   return android::base::StringPrintf("%d: calloc %p %zu %zu\n", tid_, pointer_, nmemb_, size_);
 }
 
 ReallocEntry::ReallocEntry(void* pointer, size_t size, void* old_pointer)
-    : MallocEntry(pointer, size), old_pointer_(old_pointer) {
-}
+    : MallocEntry(pointer, size), old_pointer_(old_pointer) {}
 
 std::string ReallocEntry::GetString() const {
-  return android::base::StringPrintf("%d: realloc %p %p %zu\n", tid_, pointer_,
-                                     old_pointer_, size_);
+  return android::base::StringPrintf("%d: realloc %p %p %zu\n", tid_, pointer_, old_pointer_, size_);
 }
 
 // aligned_alloc, posix_memalign, memalign, pvalloc, valloc all recorded with this class.
 MemalignEntry::MemalignEntry(void* pointer, size_t size, size_t alignment)
-    : MallocEntry(pointer, size), alignment_(alignment) {
-}
+    : MallocEntry(pointer, size), alignment_(alignment) {}
 
 std::string MemalignEntry::GetString() const {
-  return android::base::StringPrintf("%d: memalign %p %zu %zu\n", tid_, pointer_,
-                                     alignment_, size_);
+  return android::base::StringPrintf("%d: memalign %p %zu %zu\n", tid_, pointer_, alignment_, size_);
 }
 
 struct ThreadData {
-  ThreadData(RecordData* record_data, ThreadCompleteEntry* entry) : record_data(record_data), entry(entry) {}
+  ThreadData(RecordData* record_data, ThreadCompleteEntry* entry)
+      : record_data(record_data), entry(entry) {}
   RecordData* record_data;
   ThreadCompleteEntry* entry;
   size_t count = 0;
@@ -141,8 +134,8 @@
     last_entry_index = num_entries_;
   }
 
-  int dump_fd = open(dump_file_.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
-                     0755);
+  int dump_fd =
+      open(dump_file_.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0755);
   if (dump_fd != -1) {
     for (size_t i = 0; i < last_entry_index; i++) {
       std::string line = entries_[i]->GetString();
@@ -201,7 +194,7 @@
 }
 
 RecordData::~RecordData() {
-  delete [] entries_;
+  delete[] entries_;
   pthread_key_delete(key_);
 }
 
diff --git a/libc/malloc_debug/RecordData.h b/libc/malloc_debug/RecordData.h
index 021a299..3e5ca02 100644
--- a/libc/malloc_debug/RecordData.h
+++ b/libc/malloc_debug/RecordData.h
@@ -28,8 +28,8 @@
 
 #pragma once
 
-#include <stdint.h>
 #include <pthread.h>
+#include <stdint.h>
 #include <unistd.h>
 
 #include <atomic>
diff --git a/libc/malloc_debug/TrackData.cpp b/libc/malloc_debug/TrackData.cpp
deleted file mode 100644
index 4266aa2..0000000
--- a/libc/malloc_debug/TrackData.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <pthread.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <algorithm>
-#include <vector>
-
-#include <private/ScopedPthreadMutexLocker.h>
-
-#include "backtrace.h"
-#include "BacktraceData.h"
-#include "Config.h"
-#include "DebugData.h"
-#include "debug_disable.h"
-#include "debug_log.h"
-#include "malloc_debug.h"
-#include "TrackData.h"
-
-TrackData::TrackData(DebugData* debug_data) : OptionData(debug_data) {
-}
-
-void TrackData::GetList(std::vector<const Header*>* list) {
-  for (const auto& header : headers_) {
-    list->push_back(header);
-  }
-
-  // Sort by the size of the allocation.
-  std::sort(list->begin(), list->end(), [](const Header* a, const Header* b) {
-    if (a->size == b->size) return a < b;
-    return a->size > b->size;
-  });
-}
-
-void TrackData::GetListBySizeThenBacktrace(std::vector<const Header*>* list, size_t* total_memory) {
-  if (!(debug_->config().options() & BACKTRACE)) {
-    return;
-  }
-
-  *total_memory = 0;
-  for (const auto& header : headers_) {
-    list->push_back(header);
-    *total_memory += header->real_size();
-  }
-
-  // Put all zygote allocations first by size and backtrace.
-  // Then all zygote child allocation by size and backtrace.
-  std::sort(list->begin(), list->end(), [&](const Header* a, const Header* b) {
-    if (a->zygote_child_alloc() && !b->zygote_child_alloc()) {
-      return false;
-    } else if (!a->zygote_child_alloc() && b->zygote_child_alloc()) {
-      return true;
-    }
-    if (a->real_size() != b->real_size()) return a->real_size() < b->real_size();
-    // If the size is the same, compare backtrace elements.
-    BacktraceHeader* a_back = debug_->GetAllocBacktrace(a);
-    BacktraceHeader* b_back = debug_->GetAllocBacktrace(b);
-    for (size_t i = 0; i < a_back->num_frames; i++) {
-      if (i > b_back->num_frames) {
-        // All frames equal up to this point, but a has more frames available.
-        return false;
-      }
-      if (a_back->frames[i] < b_back->frames[i]) {
-        return false;
-      } else if (a_back->frames[i] > b_back->frames[i]) {
-        return true;
-      }
-    }
-    if (a_back->num_frames < b_back->num_frames) {
-      // All frames equal up to this point, but b has more frames available.
-      return true;
-    }
-    return false;
-  });
-
-}
-
-void TrackData::Add(const Header* header, bool backtrace_found) {
-  pthread_mutex_lock(&mutex_);
-  if (backtrace_found) {
-    total_backtrace_allocs_++;
-  }
-  headers_.insert(header);
-  pthread_mutex_unlock(&mutex_);
-}
-
-void TrackData::Remove(const Header* header, bool backtrace_found) {
-  pthread_mutex_lock(&mutex_);
-  headers_.erase(header);
-  if (backtrace_found) {
-    total_backtrace_allocs_--;
-  }
-  pthread_mutex_unlock(&mutex_);
-}
-
-bool TrackData::Contains(const Header* header) {
-  pthread_mutex_lock(&mutex_);
-  bool found = headers_.count(header);
-  pthread_mutex_unlock(&mutex_);
-  return found;
-}
-
-void TrackData::DisplayLeaks() {
-  std::vector<const Header*> list;
-  GetList(&list);
-
-  size_t track_count = 0;
-  for (const auto& header : list) {
-    error_log("+++ %s leaked block of size %zu at %p (leak %zu of %zu)", getprogname(),
-              header->real_size(), debug_->GetPointer(header), ++track_count, list.size());
-    if (debug_->config().options() & BACKTRACE) {
-      BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);
-      if (back_header->num_frames > 0) {
-        error_log("Backtrace at time of allocation:");
-        backtrace_log(&back_header->frames[0], back_header->num_frames);
-      }
-    }
-    g_dispatch->free(header->orig_pointer);
-  }
-}
-
-void TrackData::GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
-                        size_t* total_memory, size_t* backtrace_size) {
-  ScopedPthreadMutexLocker scoped(&mutex_);
-
-  if (headers_.size() == 0 || total_backtrace_allocs_ == 0) {
-    return;
-  }
-
-  *backtrace_size = debug_->config().backtrace_frames();
-  *info_size = sizeof(size_t) * 2 + sizeof(uintptr_t) * *backtrace_size;
-  *info = reinterpret_cast<uint8_t*>(g_dispatch->calloc(*info_size, total_backtrace_allocs_));
-  if (*info == nullptr) {
-    return;
-  }
-  *overall_size = *info_size * total_backtrace_allocs_;
-
-  std::vector<const Header*> list;
-  GetList(&list);
-
-  uint8_t* data = *info;
-  size_t num_allocations = 1;
-  for (const auto& header : list) {
-    BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);
-    if (back_header->num_frames > 0) {
-      memcpy(data, &header->size, sizeof(size_t));
-      memcpy(&data[sizeof(size_t)], &num_allocations, sizeof(size_t));
-      memcpy(&data[2 * sizeof(size_t)], &back_header->frames[0],
-            back_header->num_frames * sizeof(uintptr_t));
-
-      *total_memory += header->real_size();
-
-      data += *info_size;
-    }
-  }
-}
diff --git a/libc/malloc_debug/TrackData.h b/libc/malloc_debug/TrackData.h
deleted file mode 100644
index 7201c49..0000000
--- a/libc/malloc_debug/TrackData.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <pthread.h>
-
-#include <vector>
-#include <unordered_set>
-
-#include <private/bionic_macros.h>
-
-#include "OptionData.h"
-
-// Forward declarations.
-struct Header;
-class Config;
-class DebugData;
-
-class TrackData : public OptionData {
- public:
-  explicit TrackData(DebugData* debug_data);
-  virtual ~TrackData() = default;
-
-  void GetList(std::vector<const Header*>* list);
-
-  void GetListBySizeThenBacktrace(std::vector<const Header*>* list, size_t* total_memory);
-
-  void Add(const Header* header, bool backtrace_found);
-
-  void Remove(const Header* header, bool backtrace_found);
-
-  bool Contains(const Header *header);
-
-  void GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
-               size_t* total_memory, size_t* backtrace_size);
-
-  void DisplayLeaks();
-
-  void PrepareFork() { pthread_mutex_lock(&mutex_); }
-  void PostForkParent() { pthread_mutex_unlock(&mutex_); }
-  void PostForkChild() { pthread_mutex_init(&mutex_, NULL); }
-
- private:
-  pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
-  std::unordered_set<const Header*> headers_;
-  size_t total_backtrace_allocs_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(TrackData);
-};
diff --git a/libc/malloc_debug/backtrace.cpp b/libc/malloc_debug/backtrace.cpp
index 2443ba1..cd8c334 100644
--- a/libc/malloc_debug/backtrace.cpp
+++ b/libc/malloc_debug/backtrace.cpp
@@ -38,9 +38,9 @@
 
 #include <demangle.h>
 
+#include "MapData.h"
 #include "backtrace.h"
 #include "debug_log.h"
-#include "MapData.h"
 
 #if defined(__LP64__)
 #define PAD_PTR "016" PRIxPTR
@@ -69,8 +69,7 @@
   _Unwind_Backtrace(find_current_map, nullptr);
 }
 
-void backtrace_shutdown() {
-}
+void backtrace_shutdown() {}
 
 struct stack_crawl_state_t {
   uintptr_t* frames;
@@ -165,13 +164,13 @@
 
     char buf[1024];
     if (symbol != nullptr) {
-      async_safe_format_buffer(
-          buf, sizeof(buf), "          #%02zd  pc %" PAD_PTR "  %s%s (%s+%" PRIuPTR ")\n", frame_num,
-          rel_pc, soname, offset_buf, demangle(symbol).c_str(), frames[frame_num] - offset);
+      async_safe_format_buffer(buf, sizeof(buf),
+                               "          #%02zd  pc %" PAD_PTR "  %s%s (%s+%" PRIuPTR ")\n",
+                               frame_num, rel_pc, soname, offset_buf, demangle(symbol).c_str(),
+                               frames[frame_num] - offset);
     } else {
-      async_safe_format_buffer(
-          buf, sizeof(buf), "          #%02zd  pc %" PAD_PTR "  %s%s\n", frame_num, rel_pc, soname,
-          offset_buf);
+      async_safe_format_buffer(buf, sizeof(buf), "          #%02zd  pc %" PAD_PTR "  %s%s\n",
+                               frame_num, rel_pc, soname, offset_buf);
     }
     str += buf;
   }
diff --git a/libc/malloc_debug/debug_log.h b/libc/malloc_debug/debug_log.h
index 54dd221..d2257df 100644
--- a/libc/malloc_debug/debug_log.h
+++ b/libc/malloc_debug/debug_log.h
@@ -33,11 +33,10 @@
 // =============================================================================
 // log functions
 // =============================================================================
-#define debug_log(format, ...)  \
-    async_safe_format_log(ANDROID_LOG_DEBUG, "malloc_debug", (format), ##__VA_ARGS__ )
-#define error_log(format, ...)  \
-    async_safe_format_log(ANDROID_LOG_ERROR, "malloc_debug", (format), ##__VA_ARGS__ )
-#define error_log_string(str)  \
-    async_safe_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
-#define info_log(format, ...)  \
-    async_safe_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__ )
+#define debug_log(format, ...) \
+  async_safe_format_log(ANDROID_LOG_DEBUG, "malloc_debug", (format), ##__VA_ARGS__)
+#define error_log(format, ...) \
+  async_safe_format_log(ANDROID_LOG_ERROR, "malloc_debug", (format), ##__VA_ARGS__)
+#define error_log_string(str) async_safe_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
+#define info_log(format, ...) \
+  async_safe_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__)
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index ecfbd71..6f841ca 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -41,9 +41,9 @@
 #include <android-base/stringprintf.h>
 #include <private/bionic_malloc_dispatch.h>
 
-#include "backtrace.h"
 #include "Config.h"
 #include "DebugData.h"
+#include "backtrace.h"
 #include "debug_disable.h"
 #include "debug_log.h"
 #include "malloc_debug.h"
@@ -66,12 +66,11 @@
 __BEGIN_DECLS
 
 bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child,
-    const char* options);
+                      const char* options);
 void debug_finalize();
 bool debug_dump_heap(const char* file_name);
-void debug_get_malloc_leak_info(
-    uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory,
-    size_t* backtrace_size);
+void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size,
+                                size_t* total_memory, size_t* backtrace_size);
 ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count);
 void debug_free_malloc_leak_info(uint8_t* info);
 size_t debug_malloc_usable_size(void* pointer);
@@ -85,7 +84,7 @@
 int debug_mallopt(int param, int value);
 int debug_posix_memalign(void** memptr, size_t alignment, size_t size);
 int debug_iterate(uintptr_t base, size_t size,
-    void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
+                  void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
 void debug_malloc_disable();
 void debug_malloc_enable();
 
@@ -99,59 +98,92 @@
 
 static void InitAtfork() {
   static pthread_once_t atfork_init = PTHREAD_ONCE_INIT;
-  pthread_once(&atfork_init, [](){
+  pthread_once(&atfork_init, []() {
     pthread_atfork(
-        [](){
+        []() {
           if (g_debug != nullptr) {
             g_debug->PrepareFork();
           }
         },
-        [](){
+        []() {
           if (g_debug != nullptr) {
             g_debug->PostForkParent();
           }
         },
-        [](){
+        []() {
           if (g_debug != nullptr) {
             g_debug->PostForkChild();
           }
-        }
-    );
+        });
   });
 }
 
-static void LogTagError(const Header* header, const void* pointer, const char* name) {
+static void LogError(const void* pointer, const char* error_str) {
   error_log(LOG_DIVIDER);
-  if (header->tag == DEBUG_FREE_TAG) {
-    error_log("+++ ALLOCATION %p USED AFTER FREE (%s)", pointer, name);
-    if (g_debug->config().options() & FREE_TRACK) {
-      g_debug->free_track->LogBacktrace(header);
-    }
-  } else {
-    error_log("+++ ALLOCATION %p HAS INVALID TAG %" PRIx32 " (%s)", pointer, header->tag, name);
+  error_log("+++ ALLOCATION %p %s", pointer, error_str);
+
+  // If we are tracking already freed pointers, check to see if this is
+  // one so we can print extra information.
+  if (g_debug->config().options() & FREE_TRACK) {
+    PointerData::LogFreeBacktrace(pointer);
   }
-  error_log("Backtrace at time of failure:");
-  std::vector<uintptr_t> frames(64);
-  size_t frame_num = backtrace_get(frames.data(), frames.size());
-  frames.resize(frame_num);
-  backtrace_log(frames.data(), frames.size());
+
+  std::vector<uintptr_t> frames(128);
+  size_t num_frames = backtrace_get(frames.data(), frames.size());
+  if (num_frames == 0) {
+    error_log("Backtrace failed to get any frames.");
+  } else {
+    error_log("Backtrace at time of failure:");
+    backtrace_log(frames.data(), num_frames);
+  }
   error_log(LOG_DIVIDER);
 }
 
+static bool VerifyPointer(const void* pointer, const char* function_name) {
+  if (g_debug->HeaderEnabled()) {
+    Header* header = g_debug->GetHeader(pointer);
+    if (header->tag != DEBUG_TAG) {
+      std::string error_str;
+      if (header->tag == DEBUG_FREE_TAG) {
+        error_str = std::string("USED AFTER FREE (") + function_name + ")";
+      } else {
+        error_str = android::base::StringPrintf("HAS INVALID TAG %" PRIx32 " (%s)", header->tag,
+                                                function_name);
+      }
+      LogError(pointer, error_str.c_str());
+      return false;
+    }
+  }
+
+  if (g_debug->TrackPointers()) {
+    if (!PointerData::Exists(pointer)) {
+      std::string error_str(std::string("UNKNOWN POINTER (") + function_name + ")");
+      LogError(pointer, error_str.c_str());
+      return false;
+    }
+  }
+  return true;
+}
+
+static size_t InternalMallocUsableSize(void* pointer) {
+  if (g_debug->HeaderEnabled()) {
+    return g_debug->GetHeader(pointer)->usable_size;
+  } else {
+    return g_dispatch->malloc_usable_size(pointer);
+  }
+}
+
 static void* InitHeader(Header* header, void* orig_pointer, size_t size) {
   header->tag = DEBUG_TAG;
   header->orig_pointer = orig_pointer;
   header->size = size;
-  if (*g_malloc_zygote_child) {
-    header->set_zygote_child_alloc();
-  }
   header->usable_size = g_dispatch->malloc_usable_size(orig_pointer);
   if (header->usable_size == 0) {
     g_dispatch->free(orig_pointer);
     return nullptr;
   }
-  header->usable_size -= g_debug->pointer_offset() +
-      reinterpret_cast<uintptr_t>(header) - reinterpret_cast<uintptr_t>(orig_pointer);
+  header->usable_size -= g_debug->pointer_offset() + reinterpret_cast<uintptr_t>(header) -
+                         reinterpret_cast<uintptr_t>(orig_pointer);
 
   if (g_debug->config().options() & FRONT_GUARD) {
     uint8_t* guard = g_debug->GetFrontGuard(header);
@@ -163,30 +195,14 @@
     memset(guard, g_debug->config().rear_guard_value(), g_debug->config().rear_guard_bytes());
     // If the rear guard is enabled, set the usable size to the exact size
     // of the allocation.
-    header->usable_size = header->real_size();
-  }
-
-  bool backtrace_found = false;
-  if (g_debug->config().options() & BACKTRACE) {
-    BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
-    if (g_debug->backtrace->ShouldBacktrace()) {
-      back_header->num_frames = backtrace_get(
-          &back_header->frames[0], g_debug->config().backtrace_frames());
-      backtrace_found = back_header->num_frames > 0;
-    } else {
-      back_header->num_frames = 0;
-    }
-  }
-
-  if (g_debug->config().options() & TRACK_ALLOCS) {
-    g_debug->track->Add(header, backtrace_found);
+    header->usable_size = header->size;
   }
 
   return g_debug->GetPointer(header);
 }
 
 bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child,
-    const char* options) {
+                      const char* options) {
   if (malloc_zygote_child == nullptr || options == nullptr) {
     return false;
   }
@@ -222,18 +238,19 @@
   }
 
   if (g_debug->config().options() & FREE_TRACK) {
-    g_debug->free_track->VerifyAll();
+    PointerData::VerifyAllFreed();
   }
 
   if (g_debug->config().options() & LEAK_TRACK) {
-    g_debug->track->DisplayLeaks();
+    PointerData::LogLeaks();
   }
 
   if ((g_debug->config().options() & BACKTRACE) && g_debug->config().backtrace_dump_on_exit()) {
     ScopedDisableDebugCalls disable;
-    debug_dump_heap(
-        android::base::StringPrintf("%s.%d.exit.txt",
-                                    g_debug->config().backtrace_dump_prefix().c_str(),                              getpid()).c_str());
+    debug_dump_heap(android::base::StringPrintf("%s.%d.exit.txt",
+                                                g_debug->config().backtrace_dump_prefix().c_str(),
+                                                getpid())
+                        .c_str());
   }
 
   DebugDisableSet(true);
@@ -246,13 +263,13 @@
   DebugDisableFinalize();
 }
 
-void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size,
-    size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
+void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size,
+                                size_t* total_memory, size_t* backtrace_size) {
   ScopedDisableDebugCalls disable;
 
   // Verify the arguments.
-  if (info == nullptr || overall_size == nullptr || info_size == NULL ||
-      total_memory == nullptr || backtrace_size == nullptr) {
+  if (info == nullptr || overall_size == nullptr || info_size == NULL || total_memory == nullptr ||
+      backtrace_size == nullptr) {
     error_log("get_malloc_leak_info: At least one invalid parameter.");
     return;
   }
@@ -264,47 +281,37 @@
   *backtrace_size = 0;
 
   if (!(g_debug->config().options() & BACKTRACE)) {
-    error_log("get_malloc_leak_info: Allocations not being tracked, to enable "
-              "set the option 'backtrace'.");
+    error_log(
+        "get_malloc_leak_info: Allocations not being tracked, to enable "
+        "set the option 'backtrace'.");
     return;
   }
 
-  g_debug->track->GetInfo(info, overall_size, info_size, total_memory, backtrace_size);
+  PointerData::GetInfo(info, overall_size, info_size, total_memory, backtrace_size);
 }
 
 void debug_free_malloc_leak_info(uint8_t* info) {
   g_dispatch->free(info);
 }
 
-static size_t internal_malloc_usable_size(void* pointer) {
-  if (g_debug->need_header()) {
-    Header* header = g_debug->GetHeader(pointer);
-    if (header->tag != DEBUG_TAG) {
-      LogTagError(header, pointer, "malloc_usable_size");
-      return 0;
-    }
-
-    return header->usable_size;
-  } else {
-    return g_dispatch->malloc_usable_size(pointer);
-  }
-}
-
 size_t debug_malloc_usable_size(void* pointer) {
   if (DebugCallsDisabled() || pointer == nullptr) {
     return g_dispatch->malloc_usable_size(pointer);
   }
   ScopedDisableDebugCalls disable;
 
-  return internal_malloc_usable_size(pointer);
+  if (!VerifyPointer(pointer, "malloc_usable_size")) {
+    return 0;
+  }
+
+  return InternalMallocUsableSize(pointer);
 }
 
-static void *internal_malloc(size_t size) {
-  if ((g_debug->config().options() & BACKTRACE) && g_debug->backtrace->ShouldDumpAndReset()) {
-    debug_dump_heap(
-        android::base::StringPrintf("%s.%d.txt",
-                                    g_debug->config().backtrace_dump_prefix().c_str(),
-                                    getpid()).c_str());
+static void* InternalMalloc(size_t size) {
+  if ((g_debug->config().options() & BACKTRACE) && g_debug->pointer->ShouldDumpAndReset()) {
+    debug_dump_heap(android::base::StringPrintf(
+                        "%s.%d.txt", g_debug->config().backtrace_dump_prefix().c_str(), getpid())
+                        .c_str());
   }
 
   if (size == 0) {
@@ -318,15 +325,15 @@
     return nullptr;
   }
 
-  void* pointer;
-  if (g_debug->need_header()) {
-    if (size > Header::max_size()) {
-      errno = ENOMEM;
-      return nullptr;
-    }
+  if (size > PointerInfoType::MaxSize()) {
+    errno = ENOMEM;
+    return nullptr;
+  }
 
-    Header* header = reinterpret_cast<Header*>(
-        g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
+  void* pointer;
+  if (g_debug->HeaderEnabled()) {
+    Header* header =
+        reinterpret_cast<Header*>(g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
     if (header == nullptr) {
       return nullptr;
     }
@@ -335,11 +342,17 @@
     pointer = g_dispatch->malloc(real_size);
   }
 
-  if (pointer != nullptr && g_debug->config().options() & FILL_ON_ALLOC) {
-    size_t bytes = internal_malloc_usable_size(pointer);
-    size_t fill_bytes = g_debug->config().fill_on_alloc_bytes();
-    bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
-    memset(pointer, g_debug->config().fill_alloc_value(), bytes);
+  if (pointer != nullptr) {
+    if (g_debug->TrackPointers()) {
+      PointerData::Add(pointer, size);
+    }
+
+    if (g_debug->config().options() & FILL_ON_ALLOC) {
+      size_t bytes = InternalMallocUsableSize(pointer);
+      size_t fill_bytes = g_debug->config().fill_on_alloc_bytes();
+      bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
+      memset(pointer, g_debug->config().fill_alloc_value(), bytes);
+    }
   }
   return pointer;
 }
@@ -350,7 +363,7 @@
   }
   ScopedDisableDebugCalls disable;
 
-  void* pointer = internal_malloc(size);
+  void* pointer = InternalMalloc(size);
 
   if (g_debug->config().options() & RECORD_ALLOCS) {
     g_debug->record->AddEntry(new MallocEntry(pointer, size));
@@ -359,23 +372,18 @@
   return pointer;
 }
 
-static void internal_free(void* pointer) {
-  if ((g_debug->config().options() & BACKTRACE) && g_debug->backtrace->ShouldDumpAndReset()) {
-    debug_dump_heap(
-        android::base::StringPrintf("%s.%d.txt",
-                                    g_debug->config().backtrace_dump_prefix().c_str(),
-                                    getpid()).c_str());
+static void InternalFree(void* pointer) {
+  if ((g_debug->config().options() & BACKTRACE) && g_debug->pointer->ShouldDumpAndReset()) {
+    debug_dump_heap(android::base::StringPrintf(
+                        "%s.%d.txt", g_debug->config().backtrace_dump_prefix().c_str(), getpid())
+                        .c_str());
   }
 
   void* free_pointer = pointer;
   size_t bytes;
   Header* header;
-  if (g_debug->need_header()) {
+  if (g_debug->HeaderEnabled()) {
     header = g_debug->GetHeader(pointer);
-    if (header->tag != DEBUG_TAG) {
-      LogTagError(header, pointer, "free");
-      return;
-    }
     free_pointer = header->orig_pointer;
 
     if (g_debug->config().options() & FRONT_GUARD) {
@@ -389,14 +397,6 @@
       }
     }
 
-    if (g_debug->config().options() & TRACK_ALLOCS) {
-      bool backtrace_found = false;
-      if (g_debug->config().options() & BACKTRACE) {
-        BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
-        backtrace_found = back_header->num_frames > 0;
-      }
-      g_debug->track->Remove(header, backtrace_found);
-    }
     header->tag = DEBUG_FREE_TAG;
 
     bytes = header->usable_size;
@@ -410,13 +410,23 @@
     memset(pointer, g_debug->config().fill_free_value(), bytes);
   }
 
+  if (g_debug->TrackPointers()) {
+    PointerData::Remove(pointer);
+  }
+
   if (g_debug->config().options() & FREE_TRACK) {
     // Do not add the allocation until we are done modifying the pointer
     // itself. This avoids a race if a lot of threads are all doing
     // frees at the same time and we wind up trying to really free this
     // pointer from another thread, while still trying to free it in
     // this function.
-    g_debug->free_track->Add(header);
+    pointer = PointerData::AddFreed(pointer);
+    if (pointer != nullptr) {
+      if (g_debug->HeaderEnabled()) {
+        pointer = g_debug->GetHeader(pointer)->orig_pointer;
+      }
+      g_dispatch->free(pointer);
+    }
   } else {
     g_dispatch->free(free_pointer);
   }
@@ -432,7 +442,11 @@
     g_debug->record->AddEntry(new FreeEntry(pointer));
   }
 
-  internal_free(pointer);
+  if (!VerifyPointer(pointer, "free")) {
+    return;
+  }
+
+  InternalFree(pointer);
 }
 
 void* debug_memalign(size_t alignment, size_t bytes) {
@@ -445,13 +459,13 @@
     bytes = 1;
   }
 
-  void* pointer;
-  if (g_debug->need_header()) {
-    if (bytes > Header::max_size()) {
-      errno = ENOMEM;
-      return nullptr;
-    }
+  if (bytes > PointerInfoType::MaxSize()) {
+    errno = ENOMEM;
+    return nullptr;
+  }
 
+  void* pointer;
+  if (g_debug->HeaderEnabled()) {
     // Make the alignment a power of two.
     if (!powerof2(alignment)) {
       alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment);
@@ -493,15 +507,21 @@
     pointer = g_dispatch->memalign(alignment, real_size);
   }
 
-  if (pointer != nullptr && g_debug->config().options() & FILL_ON_ALLOC) {
-    size_t bytes = internal_malloc_usable_size(pointer);
-    size_t fill_bytes = g_debug->config().fill_on_alloc_bytes();
-    bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
-    memset(pointer, g_debug->config().fill_alloc_value(), bytes);
-  }
+  if (pointer != nullptr) {
+    if (g_debug->TrackPointers()) {
+      PointerData::Add(pointer, bytes);
+    }
 
-  if (g_debug->config().options() & RECORD_ALLOCS) {
-    g_debug->record->AddEntry(new MemalignEntry(pointer, bytes, alignment));
+    if (g_debug->config().options() & FILL_ON_ALLOC) {
+      size_t bytes = InternalMallocUsableSize(pointer);
+      size_t fill_bytes = g_debug->config().fill_on_alloc_bytes();
+      bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
+      memset(pointer, g_debug->config().fill_alloc_value(), bytes);
+    }
+
+    if (g_debug->config().options() & RECORD_ALLOCS) {
+      g_debug->record->AddEntry(new MemalignEntry(pointer, bytes, alignment));
+    }
   }
 
   return pointer;
@@ -514,19 +534,23 @@
   ScopedDisableDebugCalls disable;
 
   if (pointer == nullptr) {
-    pointer = internal_malloc(bytes);
+    pointer = InternalMalloc(bytes);
     if (g_debug->config().options() & RECORD_ALLOCS) {
       g_debug->record->AddEntry(new ReallocEntry(pointer, bytes, nullptr));
     }
     return pointer;
   }
 
+  if (!VerifyPointer(pointer, "realloc")) {
+    return nullptr;
+  }
+
   if (bytes == 0) {
     if (g_debug->config().options() & RECORD_ALLOCS) {
       g_debug->record->AddEntry(new ReallocEntry(nullptr, bytes, pointer));
     }
 
-    internal_free(pointer);
+    InternalFree(pointer);
     return nullptr;
   }
 
@@ -540,45 +564,45 @@
     }
   }
 
+  if (bytes > PointerInfoType::MaxSize()) {
+    errno = ENOMEM;
+    return nullptr;
+  }
+
   void* new_pointer;
   size_t prev_size;
-  if (g_debug->need_header()) {
-    if (bytes > Header::max_size()) {
-      errno = ENOMEM;
-      return nullptr;
-    }
-
-    Header* header = g_debug->GetHeader(pointer);
-    if (header->tag != DEBUG_TAG) {
-      LogTagError(header, pointer, "realloc");
-      return nullptr;
-    }
-
+  if (g_debug->HeaderEnabled()) {
     // Same size, do nothing.
-    if (real_size == header->real_size()) {
-      // Do not bother recording, this is essentially a nop.
+    Header* header = g_debug->GetHeader(pointer);
+    if (real_size == header->size) {
+      if (g_debug->TrackPointers()) {
+        // Remove and re-add so that the backtrace is updated.
+        PointerData::Remove(pointer);
+        PointerData::Add(pointer, real_size);
+      }
       return pointer;
     }
 
     // Allocation is shrinking.
     if (real_size < header->usable_size) {
       header->size = real_size;
-      if (*g_malloc_zygote_child) {
-        header->set_zygote_child_alloc();
-      }
       if (g_debug->config().options() & REAR_GUARD) {
         // Don't bother allocating a smaller pointer in this case, simply
         // change the header usable_size and reset the rear guard.
-        header->usable_size = header->real_size();
+        header->usable_size = header->size;
         memset(g_debug->GetRearGuard(header), g_debug->config().rear_guard_value(),
                g_debug->config().rear_guard_bytes());
       }
-      // Do not bother recording, this is essentially a nop.
+      if (g_debug->TrackPointers()) {
+        // Remove and re-add so that the backtrace is updated.
+        PointerData::Remove(pointer);
+        PointerData::Add(pointer, real_size);
+      }
       return pointer;
     }
 
     // Allocate the new size.
-    new_pointer = internal_malloc(bytes);
+    new_pointer = InternalMalloc(bytes);
     if (new_pointer == nullptr) {
       errno = ENOMEM;
       return nullptr;
@@ -586,17 +610,25 @@
 
     prev_size = header->usable_size;
     memcpy(new_pointer, pointer, prev_size);
-    internal_free(pointer);
+    InternalFree(pointer);
   } else {
+    if (g_debug->TrackPointers()) {
+      PointerData::Remove(pointer);
+    }
+
     prev_size = g_dispatch->malloc_usable_size(pointer);
     new_pointer = g_dispatch->realloc(pointer, real_size);
     if (new_pointer == nullptr) {
       return nullptr;
     }
+
+    if (g_debug->TrackPointers()) {
+      PointerData::Add(new_pointer, real_size);
+    }
   }
 
   if (g_debug->config().options() & FILL_ON_ALLOC) {
-    size_t bytes = internal_malloc_usable_size(new_pointer);
+    size_t bytes = InternalMallocUsableSize(new_pointer);
     if (bytes > g_debug->config().fill_on_alloc_bytes()) {
       bytes = g_debug->config().fill_on_alloc_bytes();
     }
@@ -637,17 +669,16 @@
     return nullptr;
   }
 
-  void* pointer;
-  if (g_debug->need_header()) {
-    // The above check will guarantee the multiply will not overflow.
-    if (size > Header::max_size()) {
-      errno = ENOMEM;
-      return nullptr;
-    }
+  if (real_size > PointerInfoType::MaxSize()) {
+    errno = ENOMEM;
+    return nullptr;
+  }
 
+  void* pointer;
+  if (g_debug->HeaderEnabled()) {
     // Need to guarantee the alignment of the header.
-    Header* header = reinterpret_cast<Header*>(
-        g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
+    Header* header =
+        reinterpret_cast<Header*>(g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
     if (header == nullptr) {
       return nullptr;
     }
@@ -656,9 +687,14 @@
   } else {
     pointer = g_dispatch->calloc(1, real_size);
   }
+
   if (g_debug->config().options() & RECORD_ALLOCS) {
     g_debug->record->AddEntry(new CallocEntry(pointer, bytes, nmemb));
   }
+
+  if (pointer != nullptr && g_debug->TrackPointers()) {
+    PointerData::Add(pointer, size);
+  }
   return pointer;
 }
 
@@ -695,81 +731,45 @@
   return (*memptr != nullptr) ? 0 : ENOMEM;
 }
 
-int debug_iterate(uintptr_t base, size_t size,
-    void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) {
-  // Can't allocate, malloc is disabled
-  // Manual capture of the arguments to pass to the lambda below as void* arg
-  struct iterate_ctx {
-    decltype(callback) callback;
-    decltype(arg) arg;
-  } ctx = { callback, arg };
+int debug_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_t, void*),
+                  void* arg) {
+  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);
+    }
+    return 0;
+  }
 
-  return g_dispatch->iterate(base, size,
-      [](uintptr_t base, size_t size, void* arg) {
-        const iterate_ctx* ctx = reinterpret_cast<iterate_ctx*>(arg);
-        const void* pointer = reinterpret_cast<void*>(base);
-        if (g_debug->need_header()) {
-          const Header* header = reinterpret_cast<const Header*>(pointer);
-          if (g_debug->config().options() & TRACK_ALLOCS) {
-            if (g_debug->track->Contains(header)) {
-              // Return just the body of the allocation if we're sure the header exists
-              ctx->callback(reinterpret_cast<uintptr_t>(g_debug->GetPointer(header)),
-                  header->usable_size, ctx->arg);
-              return;
-            }
-          }
-        }
-        // Fall back to returning the whole allocation
-        ctx->callback(base, size, ctx->arg);
-      }, &ctx);
+  // An option that adds a header will add pointer tracking, so no need to
+  // check if headers are enabled.
+  return g_dispatch->iterate(base, size, callback, arg);
 }
 
 void debug_malloc_disable() {
   g_dispatch->malloc_disable();
-  if (g_debug->track) {
-    g_debug->track->PrepareFork();
+  if (g_debug->pointer) {
+    g_debug->pointer->PrepareFork();
   }
 }
 
 void debug_malloc_enable() {
-  if (g_debug->track) {
-    g_debug->track->PostForkParent();
+  if (g_debug->pointer) {
+    g_debug->pointer->PostForkParent();
   }
   g_dispatch->malloc_enable();
 }
 
-ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count) {
+ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t max_frames) {
   if (DebugCallsDisabled() || pointer == nullptr) {
     return 0;
   }
   ScopedDisableDebugCalls disable;
 
-  if (g_debug->need_header()) {
-    Header* header;
-    if (g_debug->config().options() & TRACK_ALLOCS) {
-      header = g_debug->GetHeader(pointer);
-      if (!g_debug->track->Contains(header)) {
-        return 0;
-      }
-    } else {
-      header = reinterpret_cast<Header*>(pointer);
-    }
-    if (header->tag != DEBUG_TAG) {
-      return 0;
-    }
-    if (g_debug->config().options() & BACKTRACE) {
-      BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
-      if (back_header->num_frames > 0) {
-        if (frame_count > back_header->num_frames) {
-          frame_count = back_header->num_frames;
-        }
-        memcpy(frames, &back_header->frames[0], frame_count * sizeof(uintptr_t));
-        return frame_count;
-      }
-    }
+  if (!(g_debug->config().options() & BACKTRACE)) {
+    return 0;
   }
-
-  return 0;
+  return PointerData::GetFrames(pointer, frames, max_frames);
 }
 
 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
@@ -821,30 +821,7 @@
 
   fprintf(fp, "Android Native Heap Dump v1.0\n\n");
 
-  std::vector<const Header*> list;
-  size_t total_memory;
-  g_debug->track->GetListBySizeThenBacktrace(&list, &total_memory);
-  fprintf(fp, "Total memory: %zu\n", total_memory);
-  fprintf(fp, "Allocation records: %zd\n", list.size());
-  fprintf(fp, "Backtrace size: %zu\n", g_debug->config().backtrace_frames());
-  fprintf(fp, "\n");
-
-  for (const auto& header : list) {
-    const BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
-    fprintf(fp, "z %d  sz %8zu  num    1  bt", (header->zygote_child_alloc()) ? 1 : 0,
-            header->real_size());
-    for (size_t i = 0; i < back_header->num_frames; i++) {
-      if (back_header->frames[i] == 0) {
-        break;
-      }
-#ifdef __LP64__
-      fprintf(fp, " %016" PRIxPTR, back_header->frames[i]);
-#else
-      fprintf(fp, " %08" PRIxPTR, back_header->frames[i]);
-#endif
-    }
-    fprintf(fp, "\n");
-  }
+  PointerData::DumpLiveToFile(fp);
 
   fprintf(fp, "MAPS\n");
   std::string content;
diff --git a/libc/malloc_debug/malloc_debug.h b/libc/malloc_debug/malloc_debug.h
index 18a6c2c..ac210e2 100644
--- a/libc/malloc_debug/malloc_debug.h
+++ b/libc/malloc_debug/malloc_debug.h
@@ -37,13 +37,10 @@
 // part of the header does not exist, the other parts of the header
 // will still be in this order.
 //   Header          (Required)
-//   BacktraceHeader (Optional: For the allocation backtrace)
 //   uint8_t data    (Optional: Front guard, will be a multiple of MINIMUM_ALIGNMENT_BYTES)
 //   allocation data
 //   uint8_t data    (Optional: End guard)
 //
-// If backtracing is enabled, then both BacktraceHeaders will be present.
-//
 // In the initialization function, offsets into the header will be set
 // for each different header location. The offsets are always from the
 // beginning of the Header section.
@@ -52,10 +49,6 @@
   void* orig_pointer;
   size_t size;
   size_t usable_size;
-  size_t real_size() const { return size & ~(1U << 31); }
-  void set_zygote_child_alloc() { size |= 1U << 31; }
-  bool zygote_child_alloc() const { return size & (1U << 31); }
-  static size_t max_size() { return (1U << 31) - 1; }
 } __attribute__((packed));
 
 struct BacktraceHeader {
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index ee8fe06..4603535 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -135,6 +135,10 @@
   "6 malloc_debug     This option only has meaning if the record_allocs options has been specified.\n"
   "6 malloc_debug     This is the name of the file to which recording information will be dumped.\n"
   "6 malloc_debug     The default is /data/local/tmp/record_allocs.txt.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   verify_pointers\n"
+  "6 malloc_debug     A lightweight way to verify that free/malloc_usable_size/realloc\n"
+  "6 malloc_debug     are passed valid pointers.\n"
 );
 
 TEST_F(MallocDebugConfigTest, unknown_option) {
@@ -250,15 +254,15 @@
 
 TEST_F(MallocDebugConfigTest, front_guard) {
   ASSERT_TRUE(InitConfig("front_guard=48")) << getFakeLogPrint();
-  ASSERT_EQ(FRONT_GUARD, config->options());
+  ASSERT_EQ(FRONT_GUARD | TRACK_ALLOCS, config->options());
   ASSERT_EQ(48U, config->front_guard_bytes());
 
   ASSERT_TRUE(InitConfig("front_guard")) << getFakeLogPrint();
-  ASSERT_EQ(FRONT_GUARD, config->options());
+  ASSERT_EQ(FRONT_GUARD | TRACK_ALLOCS, config->options());
   ASSERT_EQ(32U, config->front_guard_bytes());
 
   ASSERT_TRUE(InitConfig("front_guard=39")) << getFakeLogPrint();
-  ASSERT_EQ(FRONT_GUARD, config->options());
+  ASSERT_EQ(FRONT_GUARD | TRACK_ALLOCS, config->options());
 #if defined(__LP64__)
   ASSERT_EQ(48U, config->front_guard_bytes());
 #else
@@ -266,7 +270,7 @@
 #endif
 
   ASSERT_TRUE(InitConfig("front_guard=41")) << getFakeLogPrint();
-  ASSERT_EQ(FRONT_GUARD, config->options());
+  ASSERT_EQ(FRONT_GUARD | TRACK_ALLOCS, config->options());
   ASSERT_EQ(48U, config->front_guard_bytes());
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -275,11 +279,11 @@
 
 TEST_F(MallocDebugConfigTest, rear_guard) {
   ASSERT_TRUE(InitConfig("rear_guard=50")) << getFakeLogPrint();
-  ASSERT_EQ(REAR_GUARD, config->options());
+  ASSERT_EQ(REAR_GUARD | TRACK_ALLOCS, config->options());
   ASSERT_EQ(50U, config->rear_guard_bytes());
 
   ASSERT_TRUE(InitConfig("rear_guard")) << getFakeLogPrint();
-  ASSERT_EQ(REAR_GUARD, config->options());
+  ASSERT_EQ(REAR_GUARD | TRACK_ALLOCS, config->options());
   ASSERT_EQ(32U, config->rear_guard_bytes());
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -288,12 +292,12 @@
 
 TEST_F(MallocDebugConfigTest, guard) {
   ASSERT_TRUE(InitConfig("guard=32")) << getFakeLogPrint();
-  ASSERT_EQ(FRONT_GUARD | REAR_GUARD, config->options());
+  ASSERT_EQ(FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, config->options());
   ASSERT_EQ(32U, config->front_guard_bytes());
   ASSERT_EQ(32U, config->rear_guard_bytes());
 
   ASSERT_TRUE(InitConfig("guard")) << getFakeLogPrint();
-  ASSERT_EQ(FRONT_GUARD | REAR_GUARD, config->options());
+  ASSERT_EQ(FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, config->options());
   ASSERT_EQ(32U, config->front_guard_bytes());
   ASSERT_EQ(32U, config->rear_guard_bytes());
 
@@ -465,13 +469,13 @@
 
 TEST_F(MallocDebugConfigTest, free_track) {
   ASSERT_TRUE(InitConfig("free_track=1234")) << getFakeLogPrint();
-  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
   ASSERT_EQ(1234U, config->free_track_allocations());
   ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes());
   ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
 
   ASSERT_TRUE(InitConfig("free_track")) << getFakeLogPrint();
-  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
   ASSERT_EQ(100U, config->free_track_allocations());
   ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes());
   ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
@@ -482,20 +486,20 @@
 
 TEST_F(MallocDebugConfigTest, free_track_and_fill_on_free) {
   ASSERT_TRUE(InitConfig("free_track=1234 fill_on_free=32")) << getFakeLogPrint();
-  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
   ASSERT_EQ(1234U, config->free_track_allocations());
   ASSERT_EQ(32U, config->fill_on_free_bytes());
   ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
 
   ASSERT_TRUE(InitConfig("free_track fill_on_free=60")) << getFakeLogPrint();
-  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
   ASSERT_EQ(100U, config->free_track_allocations());
   ASSERT_EQ(60U, config->fill_on_free_bytes());
   ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
 
   // Now reverse the arguments.
   ASSERT_TRUE(InitConfig("fill_on_free=32 free_track=1234")) << getFakeLogPrint();
-  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
   ASSERT_EQ(1234U, config->free_track_allocations());
   ASSERT_EQ(32U, config->fill_on_free_bytes());
   ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
@@ -530,11 +534,11 @@
 
 TEST_F(MallocDebugConfigTest, free_track_backtrace_num_frames_and_free_track) {
   ASSERT_TRUE(InitConfig("free_track free_track_backtrace_num_frames=123")) << getFakeLogPrint();
-  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
   ASSERT_EQ(123U, config->free_track_backtrace_num_frames());
 
   ASSERT_TRUE(InitConfig("free_track free_track_backtrace_num_frames")) << getFakeLogPrint();
-  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options());
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, config->options());
   ASSERT_EQ(16U, config->free_track_backtrace_num_frames());
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -559,6 +563,24 @@
   ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
 }
 
+TEST_F(MallocDebugConfigTest, verify_pointers) {
+  ASSERT_TRUE(InitConfig("verify_pointers")) << getFakeLogPrint();
+  ASSERT_EQ(TRACK_ALLOCS, config->options());
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, verify_pointers_fail) {
+  ASSERT_FALSE(InitConfig("verify_pointers=200")) << getFakeLogPrint();
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: value set for option 'verify_pointers' "
+      "which does not take a value\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
 TEST_F(MallocDebugConfigTest, record_allocs) {
   ASSERT_TRUE(InitConfig("record_allocs=1234")) << getFakeLogPrint();
   ASSERT_EQ(RECORD_ALLOCS, config->options());
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 0e4a7d8..8b28188 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -72,15 +72,8 @@
 constexpr char DIVIDER[] =
     "6 malloc_debug *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n";
 
-constexpr uint32_t BACKTRACE_HEADER = 0x1;
-
-static size_t get_tag_offset(uint32_t flags = 0, size_t backtrace_frames = 0) {
-  size_t offset = __BIONIC_ALIGN(sizeof(Header), MINIMUM_ALIGNMENT_BYTES);
-  if (flags & BACKTRACE_HEADER) {
-    offset += __BIONIC_ALIGN(sizeof(BacktraceHeader) + sizeof(uintptr_t) * backtrace_frames,
-                             MINIMUM_ALIGNMENT_BYTES);
-  }
-  return offset;
+static size_t get_tag_offset() {
+  return __BIONIC_ALIGN(sizeof(Header), MINIMUM_ALIGNMENT_BYTES);
 }
 
 static constexpr const char RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs.txt";
@@ -111,6 +104,10 @@
 
   void BacktraceDumpOnSignal(bool trigger_with_alloc);
 
+  static size_t GetInfoEntrySize(size_t max_frames) {
+    return 2 * sizeof(size_t) + max_frames * sizeof(uintptr_t);
+  }
+
   bool initialized;
 
   int zygote;
@@ -140,6 +137,16 @@
   aligned_alloc,
 };
 
+std::string ShowDiffs(uint8_t* a, uint8_t* b, size_t size) {
+  std::string diff;
+  for (size_t i = 0; i < size; i++) {
+    if (a[i] != b[i]) {
+      diff += android::base::StringPrintf("Byte %zu: 0x%x 0x%x\n", i, a[i], b[i]);
+    }
+  }
+  return diff;
+}
+
 void VerifyAllocCalls(bool backtrace_enabled) {
   size_t alloc_size = 1024;
 
@@ -335,7 +342,8 @@
 
   uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
   ASSERT_TRUE(pointer != nullptr);
-  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0)
+      << ShowDiffs(buffer.data(), &pointer[-buffer.size()], buffer.size());
   memset(pointer, 0xff, 100);
   debug_free(pointer);
 
@@ -343,7 +351,8 @@
   for (size_t alignment = 1; alignment <= 256; alignment++) {
     pointer = reinterpret_cast<uint8_t*>(debug_memalign(alignment, 100));
     ASSERT_TRUE(pointer != nullptr);
-    ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+    ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0)
+        << ShowDiffs(buffer.data(), &pointer[-buffer.size()], buffer.size());
     size_t alignment_mask = alignment - 1;
     if (!powerof2(alignment)) {
       alignment_mask = BIONIC_ROUND_UP_POWER_OF_2(alignment) - 1;
@@ -355,7 +364,8 @@
 
   pointer = reinterpret_cast<uint8_t*>(debug_calloc(1, 100));
   ASSERT_TRUE(pointer != nullptr);
-  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0)
+      << ShowDiffs(buffer.data(), &pointer[-buffer.size()], buffer.size());
   for (size_t i = 0; i < 100; i++) {
     ASSERT_EQ(0, pointer[i]) << "debug_calloc non-zero byte at " << i;
   }
@@ -363,10 +373,12 @@
 
   pointer = reinterpret_cast<uint8_t*>(debug_realloc(nullptr, 100));
   ASSERT_TRUE(pointer != nullptr);
-  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0)
+      << ShowDiffs(buffer.data(), &pointer[-buffer.size()], buffer.size());
   memset(pointer, 0xff, 100);
   pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 200));
-  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0)
+      << ShowDiffs(buffer.data(), &pointer[-buffer.size()], buffer.size());
   memset(pointer, 0xff, 200);
   pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 0));
   ASSERT_TRUE(pointer == nullptr);
@@ -427,7 +439,8 @@
   uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
   ASSERT_TRUE(pointer != nullptr);
   ASSERT_EQ(100U, debug_malloc_usable_size(pointer));
-  ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0)
+      << ShowDiffs(buffer.data(), &pointer[100], buffer.size());
   memset(pointer, 0xff, 100);
   debug_free(pointer);
 
@@ -436,7 +449,8 @@
     pointer = reinterpret_cast<uint8_t*>(debug_memalign(alignment, 100));
     ASSERT_TRUE(pointer != nullptr);
     ASSERT_EQ(100U, debug_malloc_usable_size(pointer));
-    ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0);
+    ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0)
+        << ShowDiffs(buffer.data(), &pointer[100], buffer.size());
     size_t alignment_mask = alignment - 1;
     if (!powerof2(alignment)) {
       alignment_mask = BIONIC_ROUND_UP_POWER_OF_2(alignment) - 1;
@@ -450,7 +464,8 @@
   pointer = reinterpret_cast<uint8_t*>(debug_calloc(1, 100));
   ASSERT_TRUE(pointer != nullptr);
   ASSERT_EQ(100U, debug_malloc_usable_size(pointer));
-  ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0)
+      << ShowDiffs(buffer.data(), &pointer[100], buffer.size());
   for (size_t i = 0; i < 100; i++) {
     ASSERT_EQ(0, pointer[i]) << "debug_calloc non-zero byte at " << i;
   }
@@ -458,10 +473,12 @@
 
   pointer = reinterpret_cast<uint8_t*>(debug_realloc(nullptr, 100));
   ASSERT_TRUE(pointer != nullptr);
-  ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0)
+      << ShowDiffs(buffer.data(), &pointer[100], buffer.size());
   memset(pointer, 0xff, 100);
   pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 200));
-  ASSERT_TRUE(memcmp(buffer.data(), &pointer[200], buffer.size()) == 0);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[200], buffer.size()) == 0)
+      << ShowDiffs(buffer.data(), &pointer[200], buffer.size());
   for (size_t i = 0; i < 100; i++) {
     ASSERT_EQ(0xff, pointer[i]) << "debug_realloc not copied byte at " << i;
   }
@@ -829,7 +846,7 @@
 }
 
 TEST_F(MallocDebugTest, free_track_use_after_free_with_backtrace) {
-  Init("free_track=100");
+  Init("free_track=100 rear_guard");
 
   // Free backtrace.
   backtrace_fake_add(std::vector<uintptr_t> {0xfa, 0xeb, 0xdc});
@@ -860,7 +877,7 @@
 }
 
 TEST_F(MallocDebugTest, free_track_use_after_free_call_realloc) {
-  Init("free_track=100");
+  Init("free_track=100 rear_guard");
 
   // Free backtrace.
   backtrace_fake_add(std::vector<uintptr_t> {0xfa, 0xeb, 0xdc});
@@ -894,7 +911,7 @@
 }
 
 TEST_F(MallocDebugTest, free_track_use_after_free_call_free) {
-  Init("free_track=100");
+  Init("free_track=100 rear_guard");
 
   // Free backtrace.
   backtrace_fake_add(std::vector<uintptr_t> {0xfa, 0xeb, 0xdc});
@@ -926,7 +943,7 @@
 }
 
 TEST_F(MallocDebugTest, free_track_header_tag_corrupted) {
-  Init("free_track=100 free_track_backtrace_num_frames=0");
+  Init("free_track=100 free_track_backtrace_num_frames=0 rear_guard");
 
   uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
   ASSERT_TRUE(pointer != nullptr);
@@ -1053,7 +1070,7 @@
   Init("backtrace");
 
   // Create the expected info buffer.
-  size_t individual_size = 2 * sizeof(size_t) + 16 * sizeof(uintptr_t);
+  size_t individual_size = GetInfoEntrySize(16);
   std::vector<uint8_t> expected_info(individual_size);
   memset(expected_info.data(), 0, individual_size);
 
@@ -1082,7 +1099,8 @@
   ASSERT_EQ(individual_size, info_size);
   ASSERT_EQ(200U, total_memory);
   ASSERT_EQ(16U, backtrace_size);
-  ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0);
+  ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0)
+      << ShowDiffs(expected_info.data(), info, overall_size);
 
   debug_free_malloc_leak_info(info);
 
@@ -1099,7 +1117,7 @@
   Init("backtrace=16");
 
   // Create the expected info buffer.
-  size_t individual_size = 2 * sizeof(size_t) + 16 * sizeof(uintptr_t);
+  size_t individual_size = GetInfoEntrySize(16);
   std::vector<uint8_t> expected_info(individual_size * 3);
   memset(expected_info.data(), 0, individual_size * 3);
 
@@ -1162,7 +1180,8 @@
   ASSERT_EQ(individual_size, info_size);
   ASSERT_EQ(500U + 4100U + 9000U, total_memory);
   ASSERT_EQ(16U, backtrace_size);
-  ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0);
+  ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0)
+      << ShowDiffs(expected_info.data(), info, overall_size);
 
   debug_free_malloc_leak_info(info);
 
@@ -1177,52 +1196,13 @@
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
 
-TEST_F(MallocDebugTest, get_malloc_leak_info_multi_skip_empty_backtrace) {
-  Init("backtrace=16");
+TEST_F(MallocDebugTest, get_malloc_backtrace_with_header) {
+  Init("backtrace=16 guard");
 
-  // Create the expected info buffer.
-  size_t individual_size = 2 * sizeof(size_t) + 16 * sizeof(uintptr_t);
-  std::vector<uint8_t> expected_info(individual_size * 2);
-  memset(expected_info.data(), 0, individual_size * 2);
-
-  InfoEntry* entry0 = reinterpret_cast<InfoEntry*>(expected_info.data());
-  InfoEntry* entry1 = reinterpret_cast<InfoEntry*>(
-      reinterpret_cast<uintptr_t>(entry0) + individual_size);
-
-  // These values will be in the reverse order that we create.
-  entry1->size = 500;
-  entry1->num_allocations = 1;
-  entry1->frames[0] = 0xf;
-  entry1->frames[1] = 0xe;
-  entry1->frames[2] = 0xd;
-  entry1->frames[3] = 0xc;
-
-  backtrace_fake_add(std::vector<uintptr_t> {0xf, 0xe, 0xd, 0xc});
-
-  uint8_t* pointers[3];
-
-  pointers[0] = reinterpret_cast<uint8_t*>(debug_malloc(entry1->size));
-  ASSERT_TRUE(pointers[0] != nullptr);
-  memset(pointers[0], 0, entry1->size);
-
-  entry0->size = 4100;
-  entry0->num_allocations = 1;
-  for (size_t i = 0; i < 16; i++) {
-    entry0->frames[i] = 0xbc000 + i;
-  }
-
-  backtrace_fake_add(
-      std::vector<uintptr_t> {0xbc000, 0xbc001, 0xbc002, 0xbc003, 0xbc004, 0xbc005,
-                              0xbc006, 0xbc007, 0xbc008, 0xbc009, 0xbc00a, 0xbc00b,
-                              0xbc00c, 0xbc00d, 0xbc00e, 0xbc00f, 0xffff});
-
-  pointers[1] = reinterpret_cast<uint8_t*>(debug_malloc(entry0->size));
-  ASSERT_TRUE(pointers[1] != nullptr);
-  memset(pointers[1], 0, entry0->size);
-
-  pointers[2] = reinterpret_cast<uint8_t*>(debug_malloc(10000));
-  ASSERT_TRUE(pointers[2] != nullptr);
-  memset(pointers[2], 0, 10000);
+  void* pointer = debug_malloc(100);
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 100);
+  EXPECT_EQ(100U, debug_malloc_usable_size(pointer));
 
   uint8_t* info;
   size_t overall_size;
@@ -1231,18 +1211,18 @@
   size_t backtrace_size;
 
   debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
-  ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(individual_size * 2, overall_size);
-  ASSERT_EQ(individual_size, info_size);
-  ASSERT_EQ(500U + 4100U, total_memory);
-  ASSERT_EQ(16U, backtrace_size);
-  ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0);
-
+  EXPECT_TRUE(info != nullptr);
+  EXPECT_EQ(GetInfoEntrySize(16), overall_size);
+  EXPECT_EQ(GetInfoEntrySize(16), info_size);
+  EXPECT_EQ(100U, total_memory);
+  EXPECT_EQ(16U, backtrace_size);
   debug_free_malloc_leak_info(info);
 
-  debug_free(pointers[0]);
-  debug_free(pointers[1]);
-  debug_free(pointers[2]);
+  debug_free(pointer);
+
+  // There should be no pointers that have leaked.
+  debug_finalize();
+  initialized = false;
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log = android::base::StringPrintf(
@@ -1338,19 +1318,19 @@
       "Backtrace size: 4\n"
       "\n"
 #if defined(__LP64__)
-      "z 0  sz        5  num    1  bt 000000000000a300 000000000000b300\n"
-      "z 0  sz       10  num    1  bt 000000000000a000 000000000000b000\n"
       "z 0  sz       50  num    1  bt 000000000000a100 000000000000b200\n"
-      "z 1  sz       40  num    1  bt 0000000000000300 0000000000000400\n"
-      "z 1  sz      100  num    1  bt 0000000000000100 0000000000000200\n"
+      "z 0  sz       10  num    1  bt 000000000000a000 000000000000b000\n"
+      "z 0  sz        5  num    1  bt 000000000000a300 000000000000b300\n"
       "z 1  sz      200  num    1  bt 0000000000000500 0000000000000600\n"
+      "z 1  sz      100  num    1  bt 0000000000000100 0000000000000200\n"
+      "z 1  sz       40  num    1  bt 0000000000000300 0000000000000400\n"
 #else
-      "z 0  sz        5  num    1  bt 0000a300 0000b300\n"
-      "z 0  sz       10  num    1  bt 0000a000 0000b000\n"
       "z 0  sz       50  num    1  bt 0000a100 0000b200\n"
-      "z 1  sz       40  num    1  bt 00000300 00000400\n"
-      "z 1  sz      100  num    1  bt 00000100 00000200\n"
+      "z 0  sz       10  num    1  bt 0000a000 0000b000\n"
+      "z 0  sz        5  num    1  bt 0000a300 0000b300\n"
       "z 1  sz      200  num    1  bt 00000500 00000600\n"
+      "z 1  sz      100  num    1  bt 00000100 00000200\n"
+      "z 1  sz       40  num    1  bt 00000300 00000400\n"
 #endif
       "MAPS\n"
       "MAP_DATA\n"
@@ -1410,13 +1390,13 @@
       "Backtrace size: 4\n"
       "\n"
 #if defined(__LP64__)
-      "z 0  sz      300  num    1  bt 0000000000000100 0000000000000200\n"
-      "z 0  sz      400  num    1  bt 000000000000a000 000000000000b000\n"
       "z 0  sz      500  num    1  bt 000000000000a000 000000000000b000 000000000000c000\n"
+      "z 0  sz      400  num    1  bt 000000000000a000 000000000000b000\n"
+      "z 0  sz      300  num    1  bt 0000000000000100 0000000000000200\n"
 #else
-      "z 0  sz      300  num    1  bt 00000100 00000200\n"
-      "z 0  sz      400  num    1  bt 0000a000 0000b000\n"
       "z 0  sz      500  num    1  bt 0000a000 0000b000 0000c000\n"
+      "z 0  sz      400  num    1  bt 0000a000 0000b000\n"
+      "z 0  sz      300  num    1  bt 00000100 00000200\n"
 #endif
       "MAPS\n"
       "MAP_DATA\n"
@@ -1427,6 +1407,58 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
+TEST_F(MallocDebugTest, backtrace_dump_on_exit_shared_backtrace) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    Init("backtrace=4 backtrace_dump_on_exit");
+    backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200});
+    backtrace_fake_add(std::vector<uintptr_t> {0xa000, 0xb000, 0xc000});
+    backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200});
+
+    std::vector<void*> pointers;
+    pointers.push_back(debug_malloc(300));
+    pointers.push_back(debug_malloc(400));
+    pointers.push_back(debug_malloc(300));
+
+    // Call the exit function manually.
+    debug_finalize();
+    exit(0);
+  }
+  ASSERT_NE(-1, pid);
+  ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0)));
+
+  // Read all of the contents.
+  std::string actual;
+  std::string name = android::base::StringPrintf("%s.%d.exit.txt", BACKTRACE_DUMP_PREFIX, pid);
+  ASSERT_TRUE(android::base::ReadFileToString(name, &actual));
+  ASSERT_EQ(0, unlink(name.c_str()));
+
+  std::string sanitized(SanitizeHeapData(actual));
+
+  std::string expected =
+      "Android Native Heap Dump v1.0\n"
+      "\n"
+      "Total memory: 1000\n"
+      "Allocation records: 2\n"
+      "Backtrace size: 4\n"
+      "\n"
+#if defined(__LP64__)
+      "z 0  sz      400  num    1  bt 000000000000a000 000000000000b000 000000000000c000\n"
+      "z 0  sz      300  num    2  bt 0000000000000100 0000000000000200\n"
+#else
+      "z 0  sz      400  num    1  bt 0000a000 0000b000 0000c000\n"
+      "z 0  sz      300  num    2  bt 00000100 00000200\n"
+#endif
+      "MAPS\n"
+      "MAP_DATA\n"
+      "END\n\n";
+  ASSERT_STREQ(expected.c_str(), sanitized.c_str()) << "Actual data: \n" << actual;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+
 TEST_F(MallocDebugTest, realloc_usable_size) {
   Init("front_guard");
 
@@ -1453,7 +1485,7 @@
 TEST_F(MallocDebugTest, backtrace_enable_on_signal) {
   Init("backtrace_enable_on_signal=20");
 
-  size_t individual_size = 2 * sizeof(size_t) + 20 * sizeof(uintptr_t);
+  size_t individual_size = GetInfoEntrySize(20);
 
   backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
   backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200, 0x300, 0x400});
@@ -1532,6 +1564,198 @@
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
 
+TEST_F(MallocDebugTest, backtrace_same_stack) {
+  Init("backtrace=4");
+
+  size_t individual_size = GetInfoEntrySize(4);
+
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+
+  void* pointers[4];
+  pointers[0] = debug_malloc(10);
+  ASSERT_TRUE(pointers[0] != nullptr);
+  pointers[1] = debug_malloc(10);
+  ASSERT_TRUE(pointers[1] != nullptr);
+  pointers[2] = debug_malloc(10);
+  ASSERT_TRUE(pointers[2] != nullptr);
+  pointers[3] = debug_malloc(100);
+  ASSERT_TRUE(pointers[3] != nullptr);
+
+  uint8_t* info;
+  size_t overall_size;
+  size_t info_size;
+  size_t total_memory;
+  size_t backtrace_size;
+
+  debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+  ASSERT_TRUE(info != nullptr);
+  ASSERT_EQ(individual_size * 2, overall_size);
+  ASSERT_EQ(individual_size, info_size);
+  EXPECT_EQ(130U, total_memory);
+  EXPECT_EQ(4U, backtrace_size);
+  EXPECT_EQ(100U, *reinterpret_cast<size_t*>(&info[0]));
+  EXPECT_EQ(1U, *reinterpret_cast<size_t*>(&info[sizeof(size_t)]));
+  uintptr_t* ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t)]);
+  EXPECT_EQ(0xbc000U, ips[0]);
+  EXPECT_EQ(0xecd00U, ips[1]);
+  EXPECT_EQ(0x12000U, ips[2]);
+
+  EXPECT_EQ(10U, *reinterpret_cast<size_t*>(&info[individual_size]));
+  EXPECT_EQ(3U, *reinterpret_cast<size_t*>(&info[sizeof(size_t) + individual_size]));
+  ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t) + individual_size]);
+  EXPECT_EQ(0xbc000U, ips[0]);
+  EXPECT_EQ(0xecd00U, ips[1]);
+  EXPECT_EQ(0x12000U, ips[2]);
+
+  debug_free_malloc_leak_info(info);
+
+  debug_free(pointers[0]);
+  debug_free(pointers[1]);
+  debug_free(pointers[2]);
+  debug_free(pointers[3]);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+      SIGRTMAX - 17, getpid());
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, backtrace_same_stack_zygote) {
+  Init("backtrace=4");
+
+  size_t individual_size = GetInfoEntrySize(4);
+
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000});
+
+  zygote = 1;
+
+  void* pointers[4];
+  pointers[0] = debug_malloc(100);
+  ASSERT_TRUE(pointers[0] != nullptr);
+  pointers[1] = debug_malloc(100);
+  ASSERT_TRUE(pointers[1] != nullptr);
+  pointers[2] = debug_malloc(100);
+  ASSERT_TRUE(pointers[2] != nullptr);
+  pointers[3] = debug_malloc(100);
+  ASSERT_TRUE(pointers[3] != nullptr);
+
+  uint8_t* info;
+  size_t overall_size;
+  size_t info_size;
+  size_t total_memory;
+  size_t backtrace_size;
+
+  debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+  ASSERT_TRUE(info != nullptr);
+  ASSERT_EQ(individual_size * 2, overall_size);
+  EXPECT_EQ(individual_size, info_size);
+  EXPECT_EQ(400U, total_memory);
+  EXPECT_EQ(4U, backtrace_size);
+
+  EXPECT_EQ(0x80000064U, *reinterpret_cast<size_t*>(&info[0]));
+  EXPECT_EQ(3U, *reinterpret_cast<size_t*>(&info[sizeof(size_t)]));
+  uintptr_t* ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t)]);
+  EXPECT_EQ(0xbc000U, ips[0]);
+  EXPECT_EQ(0xecd00U, ips[1]);
+  EXPECT_EQ(0x12000U, ips[2]);
+
+  EXPECT_EQ(0x80000064U, *reinterpret_cast<size_t*>(&info[individual_size]));
+  EXPECT_EQ(1U, *reinterpret_cast<size_t*>(&info[sizeof(size_t) + individual_size]));
+  ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t) + individual_size]);
+  EXPECT_EQ(0xbc000U, ips[0]);
+  EXPECT_EQ(0U, ips[1]);
+
+  debug_free_malloc_leak_info(info);
+
+  debug_free(pointers[0]);
+  debug_free(pointers[1]);
+  debug_free(pointers[2]);
+  debug_free(pointers[3]);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+      SIGRTMAX - 17, getpid());
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, backtrace_same_stack_mix_zygote) {
+  Init("backtrace=4");
+
+  size_t individual_size = GetInfoEntrySize(4);
+
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000});
+
+  zygote = 1;
+  void* pointers[4];
+  pointers[0] = debug_malloc(40);
+  ASSERT_TRUE(pointers[0] != nullptr);
+  pointers[1] = debug_malloc(40);
+  ASSERT_TRUE(pointers[1] != nullptr);
+
+  zygote = 0;
+  pointers[2] = debug_malloc(40);
+  ASSERT_TRUE(pointers[2] != nullptr);
+  pointers[3] = debug_malloc(100);
+  ASSERT_TRUE(pointers[3] != nullptr);
+
+  uint8_t* info;
+  size_t overall_size;
+  size_t info_size;
+  size_t total_memory;
+  size_t backtrace_size;
+
+  debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+  ASSERT_TRUE(info != nullptr);
+  ASSERT_EQ(individual_size * 3, overall_size);
+  ASSERT_EQ(individual_size, info_size);
+  EXPECT_EQ(220U, total_memory);
+  EXPECT_EQ(4U, backtrace_size);
+
+  EXPECT_EQ(100U, *reinterpret_cast<size_t*>(&info[0]));
+  EXPECT_EQ(1U, *reinterpret_cast<size_t*>(&info[sizeof(size_t)]));
+  uintptr_t* ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t)]);
+  EXPECT_EQ(0xbc000U, ips[0]);
+  EXPECT_EQ(0U, ips[1]);
+
+  EXPECT_EQ(40U, *reinterpret_cast<size_t*>(&info[individual_size]));
+  EXPECT_EQ(1U, *reinterpret_cast<size_t*>(&info[sizeof(size_t) + individual_size]));
+  ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t) + individual_size]);
+  EXPECT_EQ(0xbc000U, ips[0]);
+  EXPECT_EQ(0xecd00U, ips[1]);
+  EXPECT_EQ(0x12000U, ips[2]);
+
+  EXPECT_EQ(0x80000028U, *reinterpret_cast<size_t*>(&info[2 * individual_size]));
+  EXPECT_EQ(2U, *reinterpret_cast<size_t*>(&info[sizeof(size_t) + 2 * individual_size]));
+  ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t) + 2 * individual_size]);
+  EXPECT_EQ(0xbc000U, ips[0]);
+  EXPECT_EQ(0xecd00U, ips[1]);
+  EXPECT_EQ(0x12000U, ips[2]);
+
+  debug_free_malloc_leak_info(info);
+
+  debug_free(pointers[0]);
+  debug_free(pointers[1]);
+  debug_free(pointers[2]);
+  debug_free(pointers[3]);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the backtrace.\n",
+      SIGRTMAX - 17, getpid());
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
 TEST_F(MallocDebugTest, overflow) {
   Init("guard fill_on_free");
 
@@ -1601,7 +1825,8 @@
   ASSERT_EQ(expected_info_size, info_size);
   ASSERT_EQ(memory_bytes, total_memory);
   ASSERT_EQ(16U, backtrace_size);
-  ASSERT_TRUE(memcmp(info, expected_info.data(), expected_info_size) == 0);
+  ASSERT_TRUE(memcmp(info, expected_info.data(), expected_info_size) == 0)
+      << ShowDiffs(info, expected_info.data(), expected_info_size);
 
   debug_free_malloc_leak_info(info);
 }
@@ -1619,6 +1844,7 @@
   ASSERT_EQ(100U, debug_malloc_usable_size(pointer));
   memset(pointer, 0, 100);
   VerifyZygoteSet(100);
+  ASSERT_FALSE(HasFatalFailure());
   debug_free(pointer);
 
   backtrace_fake_add(std::vector<uintptr_t> {0x1});
@@ -1626,6 +1852,7 @@
   ASSERT_TRUE(pointer != nullptr);
   ASSERT_EQ(200U, debug_malloc_usable_size(pointer));
   VerifyZygoteSet(200);
+  ASSERT_FALSE(HasFatalFailure());
   debug_free(pointer);
 
   backtrace_fake_add(std::vector<uintptr_t> {0x1});
@@ -1634,6 +1861,7 @@
   ASSERT_EQ(300U, debug_malloc_usable_size(pointer));
   memset(pointer, 0, 300);
   VerifyZygoteSet(300);
+  ASSERT_FALSE(HasFatalFailure());
   debug_free(pointer);
 
   backtrace_fake_add(std::vector<uintptr_t> {0x1});
@@ -1642,12 +1870,14 @@
   ASSERT_EQ(500U, debug_malloc_usable_size(pointer));
   memset(pointer, 0, 500);
   VerifyZygoteSet(500);
+  ASSERT_FALSE(HasFatalFailure());
 
   backtrace_fake_add(std::vector<uintptr_t> {0x1});
   pointer = debug_realloc(pointer, 300);
   ASSERT_TRUE(pointer != nullptr);
   ASSERT_EQ(300U, debug_malloc_usable_size(pointer));
   VerifyZygoteSet(300);
+  ASSERT_FALSE(HasFatalFailure());
   debug_free(pointer);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -1984,3 +2214,62 @@
       RECORD_ALLOCS_FILE);
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
+
+TEST_F(MallocDebugTest, verify_pointers) {
+  Init("verify_pointers");
+
+  void* pointer = debug_malloc(10);
+  memset(pointer, 0, 10);
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+
+  debug_free(pointer);
+  ASSERT_EQ(0U, debug_malloc_usable_size(pointer));
+  ASSERT_EQ(nullptr, debug_realloc(pointer, 1000));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string free_pointer_str(
+      android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p UNKNOWN POINTER (free)\n",
+                                  pointer));
+  std::string usable_pointer_str(
+      android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p UNKNOWN POINTER (malloc_usable_size)\n",
+                                  pointer));
+  std::string realloc_pointer_str(
+      android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p UNKNOWN POINTER (realloc)\n",
+                                  pointer));
+  std::string backtrace_str("6 malloc_debug Backtrace failed to get any frames.\n");
+
+  std::string expected_log(DIVIDER + free_pointer_str + backtrace_str + DIVIDER);
+  expected_log += DIVIDER + usable_pointer_str + backtrace_str + DIVIDER;
+  expected_log += DIVIDER + realloc_pointer_str + backtrace_str + DIVIDER;
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+
+  resetLogs();
+
+  backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200});
+  backtrace_fake_add(std::vector<uintptr_t> {0x300, 0x400});
+  backtrace_fake_add(std::vector<uintptr_t> {0x500, 0x600});
+  debug_free(pointer);
+  ASSERT_EQ(0U, debug_malloc_usable_size(pointer));
+  ASSERT_EQ(nullptr, debug_realloc(pointer, 1000));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  expected_log = DIVIDER + free_pointer_str;
+  expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+  expected_log += "6 malloc_debug   #00 pc 0x100\n";
+  expected_log += "6 malloc_debug   #01 pc 0x200\n";
+  expected_log += DIVIDER;
+  expected_log += DIVIDER + usable_pointer_str;
+  expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+  expected_log += "6 malloc_debug   #00 pc 0x300\n";
+  expected_log += "6 malloc_debug   #01 pc 0x400\n";
+  expected_log += DIVIDER;
+  expected_log += DIVIDER + realloc_pointer_str;
+  expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+  expected_log += "6 malloc_debug   #00 pc 0x500\n";
+  expected_log += "6 malloc_debug   #01 pc 0x600\n";
+  expected_log += DIVIDER;
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}