Malloc debug rewrite.

The major components of the rewrite:

- Completely remove the qemu shared library code. Nobody was using it
  and it appears to have broken at some point.
- Adds the ability to enable/disable different options independently.
- Adds a new option that can enable the backtrace on alloc/free when
  a process gets a specific signal.
- Adds a new way to enable malloc debug. If a special property is
  set, and the process has an environment variable set, then debug
  malloc will be enabled. This allows something that might be
  a derivative of app_process to be started with an environment variable
  being enabled.
- get_malloc_leak_info() used to return one element for each pointer that
  had the exact same backtrace. The new version returns information for
  every one of the pointers with same backtrace. It turns out ddms already
  automatically coalesces these, so the old method simply hid the fact
  that there where multiple pointers with the same amount of backtrace.
- Moved all of the malloc debug specific code into the library.
  Nothing related to the malloc debug data structures remains in libc.
- Removed the calls to the debug malloc cleanup routine. Instead, I
  added an atexit call with the debug malloc cleanup routine. This gets
  around most problems related to the timing of doing the cleanup.

The new properties and environment variables:

libc.debug.malloc.options
  Set by option name (such as "backtrace"). Setting this to a bad value
  will cause a usage statement to be printed to the log.

libc.debug.malloc.program
  Same as before. If this is set, then only the program named will
  be launched with malloc debug enabled. This is not a complete match,
  but if any part of the property is in the program name, malloc debug is
  enabled.

libc.debug.malloc.env_enabled
  If set, then malloc debug is only enabled if the running process has the
  environment variable LIBC_DEBUG_MALLOC_ENABLE set.

Bug: 19145921

Change-Id: I7b0e58cc85cc6d4118173fe1f8627a391b64c0d7
diff --git a/libc/malloc_debug/tests/backtrace_fake.cpp b/libc/malloc_debug/tests/backtrace_fake.cpp
new file mode 100644
index 0000000..32da696
--- /dev/null
+++ b/libc/malloc_debug/tests/backtrace_fake.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <deque>
+#include <vector>
+#include <utility>
+
+#include "backtrace.h"
+#include "backtrace_fake.h"
+#include "debug_log.h"
+
+static std::deque<std::vector<uintptr_t>> g_fake_backtrace;
+
+void backtrace_fake_clear_all() {
+  g_fake_backtrace.clear();
+}
+
+void backtrace_fake_add(const std::vector<uintptr_t>& ips) {
+  g_fake_backtrace.push_back(ips);
+}
+
+void backtrace_startup() {
+}
+
+void backtrace_shutdown() {
+}
+
+size_t backtrace_get(uintptr_t* frames, size_t frame_num) {
+  if (frame_num == 0 || g_fake_backtrace.size() == 0) {
+    return 0;
+  }
+
+  size_t ips_size = g_fake_backtrace[0].size();
+  size_t total_frames = (frame_num < ips_size) ? frame_num : ips_size;
+  memcpy(frames, g_fake_backtrace[0].data(), sizeof(uintptr_t) * total_frames);
+  g_fake_backtrace.pop_front();
+  return total_frames;
+}
+
+void backtrace_log(uintptr_t* frames, size_t frame_count) {
+  for (size_t i = 0; i < frame_count; i++) {
+    error_log("  #%02zd pc %p", i, reinterpret_cast<void*>(frames[i]));
+  }
+}
diff --git a/libc/malloc_debug/tests/backtrace_fake.h b/libc/malloc_debug/tests/backtrace_fake.h
new file mode 100644
index 0000000..f2aa7a0
--- /dev/null
+++ b/libc/malloc_debug/tests/backtrace_fake.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MALLOC_DEBUG_TESTS_BACKTRACE_FAKE_H
+#define MALLOC_DEBUG_TESTS_BACKTRACE_FAKE_H
+
+#include <stdint.h>
+
+#include <vector>
+
+void backtrace_fake_clear_all();
+void backtrace_fake_add(const std::vector<uintptr_t>& ips);
+
+#endif // MALLOC_DEBUG_TESTS_BACKTRACE_FAKE_H
diff --git a/libc/malloc_debug/tests/libc_fake.cpp b/libc/malloc_debug/tests/libc_fake.cpp
new file mode 100644
index 0000000..45ace4d
--- /dev/null
+++ b/libc/malloc_debug/tests/libc_fake.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" const char* getprogname() {
+  return "malloc_testing";
+}
diff --git a/libc/malloc_debug/tests/log_fake.cpp b/libc/malloc_debug/tests/log_fake.cpp
new file mode 100644
index 0000000..7350ea0
--- /dev/null
+++ b/libc/malloc_debug/tests/log_fake.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <log/logger.h>
+
+// Forward declarations.
+class Backtrace;
+struct EventTagMap;
+struct AndroidLogEntry;
+
+std::string g_fake_log_buf;
+
+std::string g_fake_log_print;
+
+void resetLogs() {
+  g_fake_log_buf = "";
+  g_fake_log_print = "";
+}
+
+std::string getFakeLogBuf() {
+  return g_fake_log_buf;
+}
+
+std::string getFakeLogPrint() {
+  return g_fake_log_print;
+}
+
+extern "C" int __libc_format_log(int priority, const char* tag, const char* format, ...) {
+  g_fake_log_print += std::to_string(priority) + ' ';
+  g_fake_log_print += tag;
+  g_fake_log_print += ' ';
+
+  va_list ap;
+  va_start(ap, format);
+  android::base::StringAppendV(&g_fake_log_print, format, ap);
+  va_end(ap);
+
+  g_fake_log_print += '\n';
+
+  return 0;
+}
+
+extern "C" int __android_log_buf_write(int bufId, int prio, const char* tag, const char* msg) {
+  g_fake_log_buf += std::to_string(bufId) + ' ' + std::to_string(prio) + ' ';
+  g_fake_log_buf += tag;
+  g_fake_log_buf += ' ';
+  g_fake_log_buf += msg;
+  return 1;
+}
+
+extern "C" int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
+  g_fake_log_print += std::to_string(prio) + ' ';
+  g_fake_log_print += tag;
+  g_fake_log_print += ' ';
+
+  va_list ap;
+  va_start(ap, fmt);
+  android::base::StringAppendV(&g_fake_log_print, fmt, ap);
+  va_end(ap);
+
+  g_fake_log_print += '\n';
+
+  return 1;
+}
+
+extern "C" log_id_t android_name_to_log_id(const char*) {
+  return LOG_ID_SYSTEM;
+}
+
+extern "C" struct logger_list* android_logger_list_open(log_id_t, int, unsigned int, pid_t) {
+  errno = EACCES;
+  return nullptr;
+}
+
+extern "C" int android_logger_list_read(struct logger_list*, struct log_msg*) {
+  return 0;
+}
+
+extern "C" EventTagMap* android_openEventTagMap(const char*) {
+  return nullptr;
+}
+
+extern "C" int android_log_processBinaryLogBuffer(
+    struct logger_entry*,
+    AndroidLogEntry*, const EventTagMap*, char*, int) {
+  return 0;
+}
+
+extern "C" void android_logger_list_free(struct logger_list*) {
+}
diff --git a/libc/malloc_debug/tests/log_fake.h b/libc/malloc_debug/tests/log_fake.h
new file mode 100644
index 0000000..1ea72f8
--- /dev/null
+++ b/libc/malloc_debug/tests/log_fake.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MALLOC_DEBUG_TESTS_LOG_FAKE_H
+#define MALLOC_DEBUG_TESTS_LOG_FAKE_H
+
+#include <string>
+
+void resetLogs();
+std::string getFakeLogBuf();
+std::string getFakeLogPrint();
+
+#endif // MALLOC_DEBUG_TESTS_LOG_FAKE_H
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
new file mode 100644
index 0000000..ad25948
--- /dev/null
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits.h>
+
+#include <memory>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "Config.h"
+
+#include "log_fake.h"
+
+extern "C" int property_set(const char*, const char*);
+
+class MallocDebugConfigTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    resetLogs();
+  }
+
+  void TearDown() override {
+  }
+
+  std::unique_ptr<Config> config;
+
+  bool InitConfig(const char* property_value) {
+    config.reset(new Config);
+    property_set("libc.debug.malloc.options", property_value);
+    return config->SetFromProperties();
+  }
+};
+
+std::string usage_string(
+  "6 malloc_debug malloc debug options usage:\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   front_guard[=XX]\n"
+  "6 malloc_debug     Enables a front guard on all allocations. If XX is set\n"
+  "6 malloc_debug     it sets the number of bytes in the guard. The default is\n"
+  "6 malloc_debug     32 bytes.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   rear_guard[=XX]\n"
+  "6 malloc_debug     Enables a rear guard on all allocations. If XX is set\n"
+  "6 malloc_debug     it sets the number of bytes in the guard. The default is\n"
+  "6 malloc_debug     32 bytes.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   guard[=XX]\n"
+  "6 malloc_debug     Enables both a front guard and a rear guard on all allocations.\n"
+  "6 malloc_debug     If XX is set it sets the number of bytes in both guards.\n"
+  "6 malloc_debug     The default is 32 bytes.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   backtrace[=XX]\n"
+  "6 malloc_debug     Enable capturing the backtrace at the point of allocation.\n"
+  "6 malloc_debug     If XX is set it sets the number of backtrace frames.\n"
+  "6 malloc_debug     The default is 16 frames.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   backtrace_enable_on_signal[=XX]\n"
+  "6 malloc_debug     Enable capturing the backtrace at the point of allocation.\n"
+  "6 malloc_debug     The backtrace capture is not enabled until the process\n"
+  "6 malloc_debug     receives a signal. If XX is set it sets the number of backtrace\n"
+  "6 malloc_debug     frames. The default is 16 frames.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   fill_on_alloc[=XX]\n"
+  "6 malloc_debug     On first allocation, fill with the value 0xeb.\n"
+  "6 malloc_debug     If XX is set it will only fill up to XX bytes of the\n"
+  "6 malloc_debug     allocation. The default is to fill the entire allocation.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   fill_on_free[=XX]\n"
+  "6 malloc_debug     On free, fill with the value 0xef. If XX is set it will\n"
+  "6 malloc_debug     only fill up to XX bytes of the allocation. The default is to\n"
+  "6 malloc_debug     fill the entire allocation.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   fill[=XX]\n"
+  "6 malloc_debug     On both first allocation free, fill with the value 0xeb on\n"
+  "6 malloc_debug     first allocation and the value 0xef. If XX is set, only fill\n"
+  "6 malloc_debug     up to XX bytes. The default is to fill the entire allocation.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   expand_alloc[=XX]\n"
+  "6 malloc_debug     Allocate an extra number of bytes for every allocation call.\n"
+  "6 malloc_debug     If XX is set, that is the number of bytes to expand the\n"
+  "6 malloc_debug     allocation by. The default is 16 bytes.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   free_track[=XX]\n"
+  "6 malloc_debug     When a pointer is freed, do not free the memory right away.\n"
+  "6 malloc_debug     Instead, keep XX of these allocations around and then verify\n"
+  "6 malloc_debug     that they have not been modified when the total number of freed\n"
+  "6 malloc_debug     allocations exceeds the XX amount. When the program terminates,\n"
+  "6 malloc_debug     the rest of these allocations are verified.\n"
+  "6 malloc_debug     The default is to record 100 allocations.\n"
+  "6 malloc_debug \n"
+  "6 malloc_debug   leak_track\n"
+  "6 malloc_debug     Enable the leak tracking of memory allocations.\n"
+);
+
+TEST_F(MallocDebugConfigTest, unknown_option) {
+
+  ASSERT_FALSE(InitConfig("unknown_option"));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg("6 malloc_debug malloc_testing: unknown option unknown_option\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, unparseable_number) {
+  ASSERT_FALSE(InitConfig("backtrace=XXX"));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace'\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, illegal_value_zero) {
+  ASSERT_FALSE(InitConfig("backtrace=0"));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace', value must be > 0: 0\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, no_space) {
+  ASSERT_FALSE(InitConfig("backtrace=10front_guard"));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: bad value for option 'backtrace', "
+      "non space found after option: front_guard\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, illegal_value_negative) {
+  ASSERT_FALSE(InitConfig("backtrace=-1"));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace', value must be > 0: -1\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, overflow) {
+  ASSERT_FALSE(InitConfig("backtrace=99999999999999999999"));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: bad value for option 'backtrace': "
+      "Math result not representable\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, set_value_error) {
+  ASSERT_FALSE(InitConfig("leak_track=12"));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: value set for option 'leak_track' "
+      "which does not take a value\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, space_before_equal) {
+  ASSERT_TRUE(InitConfig("backtrace  =10"));
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options);
+  ASSERT_EQ(10U, config->backtrace_frames);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, space_after_equal) {
+  ASSERT_TRUE(InitConfig("backtrace=  10"));
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options);
+  ASSERT_EQ(10U, config->backtrace_frames);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, extra_space) {
+  ASSERT_TRUE(InitConfig("   backtrace=64   "));
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options);
+  ASSERT_EQ(64U, config->backtrace_frames);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, multiple_options) {
+  ASSERT_TRUE(InitConfig("  backtrace=64   front_guard=24"));
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS | FRONT_GUARD, config->options);
+  ASSERT_EQ(64U, config->backtrace_frames);
+  ASSERT_EQ(24U, config->front_guard_bytes);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, front_guard) {
+  ASSERT_TRUE(InitConfig("front_guard=24"));
+  ASSERT_EQ(FRONT_GUARD, config->options);
+  ASSERT_EQ(24U, config->front_guard_bytes);
+
+  ASSERT_TRUE(InitConfig("front_guard"));
+  ASSERT_EQ(FRONT_GUARD, config->options);
+  ASSERT_EQ(32U, config->front_guard_bytes);
+
+  ASSERT_TRUE(InitConfig("front_guard=39"));
+  ASSERT_EQ(FRONT_GUARD, config->options);
+  ASSERT_EQ(40U, config->front_guard_bytes);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, rear_guard) {
+  ASSERT_TRUE(InitConfig("rear_guard=50"));
+  ASSERT_EQ(REAR_GUARD, config->options);
+  ASSERT_EQ(50U, config->rear_guard_bytes);
+
+  ASSERT_TRUE(InitConfig("rear_guard"));
+  ASSERT_EQ(REAR_GUARD, config->options);
+  ASSERT_EQ(32U, config->rear_guard_bytes);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, guard) {
+  ASSERT_TRUE(InitConfig("guard=32"));
+  ASSERT_EQ(FRONT_GUARD | REAR_GUARD, config->options);
+  ASSERT_EQ(32U, config->front_guard_bytes);
+  ASSERT_EQ(32U, config->rear_guard_bytes);
+
+  ASSERT_TRUE(InitConfig("guard"));
+  ASSERT_EQ(FRONT_GUARD | REAR_GUARD, config->options);
+  ASSERT_EQ(32U, config->front_guard_bytes);
+  ASSERT_EQ(32U, config->rear_guard_bytes);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, backtrace) {
+  ASSERT_TRUE(InitConfig("backtrace=64"));
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options);
+  ASSERT_EQ(64U, config->backtrace_frames);
+
+  ASSERT_TRUE(InitConfig("backtrace"));
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options);
+  ASSERT_EQ(16U, config->backtrace_frames);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, backtrace_enable_on_signal) {
+  ASSERT_TRUE(InitConfig("backtrace_enable_on_signal=64"));
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options);
+  ASSERT_EQ(64U, config->backtrace_frames);
+
+  ASSERT_TRUE(InitConfig("backtrace_enable_on_signal"));
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options);
+  ASSERT_EQ(16U, config->backtrace_frames);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, fill_on_alloc) {
+  ASSERT_TRUE(InitConfig("fill_on_alloc=64"));
+  ASSERT_EQ(FILL_ON_ALLOC, config->options);
+  ASSERT_EQ(64U, config->fill_on_alloc_bytes);
+
+  ASSERT_TRUE(InitConfig("fill_on_alloc"));
+  ASSERT_EQ(FILL_ON_ALLOC, config->options);
+  ASSERT_EQ(SIZE_MAX, config->fill_on_alloc_bytes);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, fill_on_free) {
+  ASSERT_TRUE(InitConfig("fill_on_free=64"));
+  ASSERT_EQ(FILL_ON_FREE, config->options);
+  ASSERT_EQ(64U, config->fill_on_free_bytes);
+
+  ASSERT_TRUE(InitConfig("fill_on_free"));
+  ASSERT_EQ(FILL_ON_FREE, config->options);
+  ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, fill) {
+  ASSERT_TRUE(InitConfig("fill=64"));
+  ASSERT_EQ(FILL_ON_ALLOC | FILL_ON_FREE, config->options);
+  ASSERT_EQ(64U, config->fill_on_alloc_bytes);
+  ASSERT_EQ(64U, config->fill_on_free_bytes);
+
+  ASSERT_TRUE(InitConfig("fill"));
+  ASSERT_EQ(FILL_ON_ALLOC | FILL_ON_FREE, config->options);
+  ASSERT_EQ(SIZE_MAX, config->fill_on_alloc_bytes);
+  ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, expand_alloc) {
+  ASSERT_TRUE(InitConfig("expand_alloc=1234"));
+  ASSERT_EQ(EXPAND_ALLOC, config->options);
+  ASSERT_EQ(1234U, config->expand_alloc_bytes);
+
+  ASSERT_TRUE(InitConfig("expand_alloc"));
+  ASSERT_EQ(EXPAND_ALLOC, config->options);
+  ASSERT_EQ(16U, config->expand_alloc_bytes);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, free_track) {
+  ASSERT_TRUE(InitConfig("free_track=1234"));
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
+  ASSERT_EQ(1234U, config->free_track_allocations);
+  ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes);
+
+  ASSERT_TRUE(InitConfig("free_track"));
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
+  ASSERT_EQ(100U, config->free_track_allocations);
+  ASSERT_EQ(SIZE_MAX, config->fill_on_free_bytes);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, free_track_and_fill_on_free) {
+  ASSERT_TRUE(InitConfig("free_track=1234 fill_on_free=32"));
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
+  ASSERT_EQ(1234U, config->free_track_allocations);
+  ASSERT_EQ(32U, config->fill_on_free_bytes);
+
+  ASSERT_TRUE(InitConfig("free_track fill_on_free=60"));
+  ASSERT_EQ(FREE_TRACK | FILL_ON_FREE, config->options);
+  ASSERT_EQ(100U, config->free_track_allocations);
+  ASSERT_EQ(60U, config->fill_on_free_bytes);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, leak_track) {
+  ASSERT_TRUE(InitConfig("leak_track"));
+  ASSERT_EQ(LEAK_TRACK | TRACK_ALLOCS, config->options);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, leak_track_fail) {
+  ASSERT_FALSE(InitConfig("leak_track=100"));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: value set for option 'leak_track' "
+      "which does not take a value\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
new file mode 100644
index 0000000..0e8ca68
--- /dev/null
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -0,0 +1,1391 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <malloc.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <vector>
+#include <utility>
+
+#include <gtest/gtest.h>
+
+#include <android-base/stringprintf.h>
+
+#include <private/bionic_macros.h>
+#include <private/bionic_malloc_dispatch.h>
+
+#include "malloc_debug.h"
+
+#include "log_fake.h"
+#include "backtrace_fake.h"
+
+__BEGIN_DECLS
+
+int property_set(const char*, const char*);
+bool debug_initialize(const MallocDispatch*, int*);
+void debug_finalize();
+
+void* debug_malloc(size_t);
+void debug_free(void*);
+void* debug_calloc(size_t, size_t);
+void* debug_realloc(void*, size_t);
+int debug_posix_memalign(void**, size_t, size_t);
+void* debug_memalign(size_t, size_t);
+size_t debug_malloc_usable_size(void*);
+void debug_get_malloc_leak_info(uint8_t**, size_t*, size_t*, size_t*, size_t*);
+void debug_free_malloc_leak_info(uint8_t*);
+
+struct mallinfo debug_mallinfo();
+
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+void* debug_pvalloc(size_t);
+void* debug_valloc(size_t);
+#endif
+
+__END_DECLS
+
+constexpr char DIVIDER[] =
+    "6 malloc_debug *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n";
+
+constexpr uint32_t TRACK_HEADER = 0x2;
+constexpr uint32_t BACKTRACE_HEADER = 0x4;
+
+static size_t get_tag_offset(uint32_t flags = 0, size_t backtrace_frames = 0) {
+  size_t offset = BIONIC_ALIGN(sizeof(Header), sizeof(uintptr_t));
+  if (flags & TRACK_HEADER) {
+    offset += BIONIC_ALIGN(sizeof(TrackHeader), sizeof(uintptr_t));
+  }
+  if (flags & BACKTRACE_HEADER) {
+    offset += BIONIC_ALIGN(sizeof(BacktraceHeader) + sizeof(uintptr_t) * backtrace_frames - 1, sizeof(uintptr_t));
+    offset += BIONIC_ALIGN(sizeof(BacktraceHeader) + sizeof(uintptr_t) * backtrace_frames - 1, sizeof(uintptr_t));
+  }
+  return offset;
+}
+
+class MallocDebugTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    initialized = false;
+    resetLogs();
+    backtrace_fake_clear_all();
+  }
+
+  void TearDown() override {
+    if (initialized) {
+      debug_finalize();
+    }
+  }
+
+  void Init(const char* property_value) {
+    property_set("libc.debug.malloc.options", property_value);
+    zygote = 0;
+    ASSERT_TRUE(debug_initialize(&dispatch, &zygote));
+    initialized = true;
+  }
+
+  bool initialized;
+
+  int zygote;
+
+  static MallocDispatch dispatch;
+};
+
+MallocDispatch MallocDebugTest::dispatch = {
+  .calloc = calloc,
+  .free = free,
+  .mallinfo = mallinfo,
+  .malloc = malloc,
+  .malloc_usable_size = malloc_usable_size,
+  .memalign = memalign,
+  .posix_memalign = posix_memalign,
+  .realloc = realloc,
+};
+
+void VerifyAllocCalls() {
+  size_t alloc_size = 1024;
+
+  // Verify debug_malloc.
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(alloc_size));
+  ASSERT_TRUE(pointer != nullptr);
+  for (size_t i = 0; i < debug_malloc_usable_size(pointer); i++) {
+    ASSERT_EQ(0xeb, pointer[i]);
+  }
+  debug_free(pointer);
+
+  // Verify debug_calloc.
+  pointer = reinterpret_cast<uint8_t*>(debug_calloc(1, alloc_size));
+  ASSERT_TRUE(pointer != nullptr);
+  for (size_t i = 0; i < debug_malloc_usable_size(pointer); i++) {
+    ASSERT_EQ(0, pointer[i]) << "Failed at byte " << i;
+  }
+  debug_free(pointer);
+
+  pointer = reinterpret_cast<uint8_t*>(debug_memalign(128, alloc_size));
+  ASSERT_TRUE(pointer != nullptr);
+  for (size_t i = 0; i < debug_malloc_usable_size(pointer); i++) {
+    ASSERT_EQ(0xeb, pointer[i]) << "Failed at byte " << i;
+  }
+  debug_free(pointer);
+
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(nullptr, alloc_size));
+  ASSERT_TRUE(pointer != nullptr);
+  for (size_t i = 0; i < debug_malloc_usable_size(pointer); i++) {
+    ASSERT_EQ(0xeb, pointer[i]) << "Failed at byte " << i;
+  }
+  memset(pointer, 0xff, alloc_size);
+  // Increase the size, verify the extra length is initialized to 0xeb,
+  // but the rest is 0xff.
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, alloc_size * 2));
+  ASSERT_TRUE(pointer != nullptr);
+  for (size_t i = 0; i < alloc_size; i++) {
+    ASSERT_EQ(0xff, pointer[i]) << "Failed at byte " << i;
+  }
+  for (size_t i = alloc_size; i < debug_malloc_usable_size(pointer); i++) {
+    ASSERT_EQ(0xeb, pointer[i]) << "Failed at byte " << i;
+  }
+  memset(pointer, 0xff, debug_malloc_usable_size(pointer));
+  // Shrink the size and verify nothing changes.
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, alloc_size));
+  ASSERT_TRUE(pointer != nullptr);
+  for (size_t i = 0; i < debug_malloc_usable_size(pointer); i++) {
+    ASSERT_EQ(0xff, pointer[i]) << "Failed at byte " << i;
+  }
+  // This should free the pointer.
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 0));
+  ASSERT_TRUE(pointer == nullptr);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, fill_generic) {
+  Init("fill");
+  VerifyAllocCalls();
+}
+
+TEST_F(MallocDebugTest, fill_on_alloc_generic) {
+  Init("fill_on_alloc");
+  VerifyAllocCalls();
+}
+
+TEST_F(MallocDebugTest, fill_on_alloc_partial) {
+  Init("fill_on_alloc=25");
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  for (size_t i = 0; i < 25; i++) {
+    ASSERT_EQ(0xeb, pointer[i]) << "Failed at byte " << i;
+  }
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, fill_on_free) {
+  Init("fill_on_free free_track");
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  size_t usable_size = debug_malloc_usable_size(pointer);
+  memset(pointer, 0, usable_size);
+  debug_free(pointer);
+
+  for (size_t i = 0; i < usable_size; i++) {
+    ASSERT_EQ(0xef, pointer[i]) << "Failed at byte " << i;
+  }
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, fill_on_free_partial) {
+  Init("fill_on_free=30 free_track");
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  size_t usable_size = debug_malloc_usable_size(pointer);
+  memset(pointer, 0, usable_size);
+  debug_free(pointer);
+
+  for (size_t i = 0; i < 30; i++) {
+    ASSERT_EQ(0xef, pointer[i]) << "Failed to fill on free at byte " << i;
+  }
+  for (size_t i = 30; i < usable_size; i++) {
+    ASSERT_EQ(0, pointer[i]) << "Filled too much on byte " << i;
+  }
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, free_track_partial) {
+  Init("fill_on_free=30 free_track");
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  size_t usable_size = debug_malloc_usable_size(pointer);
+  memset(pointer, 0, usable_size);
+  debug_free(pointer);
+
+  for (size_t i = 0; i < 30; i++) {
+    ASSERT_EQ(0xef, pointer[i]) << "Failed to fill on free at byte " << i;
+  }
+  for (size_t i = 30; i < usable_size; i++) {
+    ASSERT_EQ(0, pointer[i]) << "Filled too much on byte " << i;
+  }
+
+  debug_finalize();
+  initialized = false;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, all_options) {
+  Init("guard backtrace fill expand_alloc free_track leak_track");
+  VerifyAllocCalls();
+}
+
+TEST_F(MallocDebugTest, expand_alloc) {
+  Init("expand_alloc=1024");
+
+  void* pointer = debug_malloc(10);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_LE(1034U, debug_malloc_usable_size(pointer));
+  debug_free(pointer);
+
+  pointer = debug_calloc(1, 20);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_LE(1044U, debug_malloc_usable_size(pointer));
+  debug_free(pointer);
+
+  pointer = debug_memalign(128, 15);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_LE(1039U, debug_malloc_usable_size(pointer));
+  debug_free(pointer);
+
+  pointer = debug_realloc(nullptr, 30);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_LE(1054U, debug_malloc_usable_size(pointer));
+  pointer = debug_realloc(pointer, 100);
+  ASSERT_LE(1124U, debug_malloc_usable_size(pointer));
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, front_guard) {
+  Init("front_guard=32");
+
+  // Create a buffer for doing comparisons.
+  std::vector<uint8_t> buffer(32);
+  memset(buffer.data(), 0xaa, buffer.size());
+
+  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);
+  memset(pointer, 0xff, 100);
+  debug_free(pointer);
+
+  // Loop through a bunch alignments.
+  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);
+    size_t alignment_mask = alignment - 1;
+    if (!powerof2(alignment)) {
+      alignment_mask = BIONIC_ROUND_UP_POWER_OF_2(alignment) - 1;
+    }
+    ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(pointer) & alignment_mask);
+    memset(pointer, 0xff, 100);
+    debug_free(pointer);
+  }
+
+  pointer = reinterpret_cast<uint8_t*>(debug_calloc(1, 100));
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(0, pointer[i]) << "debug_calloc non-zero byte at " << i;
+  }
+  debug_free(pointer);
+
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(nullptr, 100));
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+  memset(pointer, 0xff, 100);
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 200));
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[-buffer.size()], buffer.size()) == 0);
+  memset(pointer, 0xff, 200);
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 0));
+  ASSERT_TRUE(pointer == nullptr);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, realloc_memalign_memory) {
+  Init("rear_guard");
+
+  void* pointer = debug_memalign(1024, 100);
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 100);
+
+  pointer = debug_realloc(pointer, 1024);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_EQ(1024U, debug_malloc_usable_size(pointer));
+  memset(pointer, 0, 1024);
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, front_guard_corrupted) {
+  Init("front_guard=32");
+
+  backtrace_fake_add(std::vector<uintptr_t> {0x1, 0x2, 0x3});
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  pointer[-32] = 0x00;
+  pointer[-15] = 0x02;
+  debug_free(pointer);
+
+  std::string expected_log(DIVIDER);
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ ALLOCATION %p SIZE 100 HAS A CORRUPTED FRONT GUARD\n", pointer);
+  expected_log += "6 malloc_debug   pointer[-32] = 0x00 (expected 0xaa)\n";
+  expected_log += "6 malloc_debug   pointer[-15] = 0x02 (expected 0xaa)\n";
+  expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+  expected_log += "6 malloc_debug   #00 pc 0x1\n";
+  expected_log += "6 malloc_debug   #01 pc 0x2\n";
+  expected_log += "6 malloc_debug   #02 pc 0x3\n";
+  expected_log += DIVIDER;
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, rear_guard) {
+  Init("rear_guard=32");
+
+  // Create a buffer for doing comparisons.
+  std::vector<uint8_t> buffer(32);
+  memset(buffer.data(), 0xbb, buffer.size());
+
+  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);
+  memset(pointer, 0xff, 100);
+  debug_free(pointer);
+
+  // Loop through a bunch alignments.
+  for (size_t alignment = 1; alignment <= 256; alignment++) {
+    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);
+    size_t alignment_mask = alignment - 1;
+    if (!powerof2(alignment)) {
+      alignment_mask = BIONIC_ROUND_UP_POWER_OF_2(alignment) - 1;
+    }
+    ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(pointer) & alignment_mask)
+        << "Failed at alignment " << alignment << " mask " << alignment_mask;
+    memset(pointer, 0xff, 100);
+    debug_free(pointer);
+  }
+
+  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);
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(0, pointer[i]) << "debug_calloc non-zero byte at " << i;
+  }
+  debug_free(pointer);
+
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(nullptr, 100));
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[100], buffer.size()) == 0);
+  memset(pointer, 0xff, 100);
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 200));
+  ASSERT_TRUE(memcmp(buffer.data(), &pointer[200], buffer.size()) == 0);
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(0xff, pointer[i]) << "debug_realloc not copied byte at " << i;
+  }
+  memset(pointer, 0xff, 200);
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 0));
+  ASSERT_TRUE(pointer == nullptr);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, rear_guard_corrupted) {
+  Init("rear_guard=32");
+
+  backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200, 0x300});
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  pointer[130] = 0xbf;
+  pointer[131] = 0x00;
+  debug_free(pointer);
+
+  std::string expected_log(DIVIDER);
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ ALLOCATION %p SIZE 100 HAS A CORRUPTED REAR GUARD\n", pointer);
+  expected_log += "6 malloc_debug   pointer[130] = 0xbf (expected 0xbb)\n";
+  expected_log += "6 malloc_debug   pointer[131] = 0x00 (expected 0xbb)\n";
+  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 += "6 malloc_debug   #02 pc 0x300\n";
+  expected_log += DIVIDER;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, rear_guard_corrupted_after_realloc_shrink) {
+  Init("rear_guard=32");
+
+  backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200, 0x300});
+
+  void* pointer = debug_malloc(200);
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 200);
+
+  uint8_t* pointer_shrink = reinterpret_cast<uint8_t*>(debug_realloc(pointer, 100));
+  pointer_shrink[130] = 0xbf;
+  pointer_shrink[131] = 0x00;
+  debug_free(pointer);
+
+  // When shrinking sizes, the same pointer should be returned.
+  ASSERT_EQ(pointer, pointer_shrink);
+
+  std::string expected_log(DIVIDER);
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ ALLOCATION %p SIZE 100 HAS A CORRUPTED REAR GUARD\n", pointer);
+  expected_log += "6 malloc_debug   pointer[130] = 0xbf (expected 0xbb)\n";
+  expected_log += "6 malloc_debug   pointer[131] = 0x00 (expected 0xbb)\n";
+  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 += "6 malloc_debug   #02 pc 0x300\n";
+  expected_log += DIVIDER;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, tag_corrupted) {
+  Init("rear_guard=32");
+
+  backtrace_fake_add(std::vector<uintptr_t> {0xa, 0xb, 0xc});
+
+  backtrace_fake_add(std::vector<uintptr_t> {0xaa, 0xbb, 0xcc});
+
+  backtrace_fake_add(std::vector<uintptr_t> {0xaaa, 0xbbb, 0xccc});
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  uint8_t saved = pointer[-get_tag_offset()];
+  pointer[-get_tag_offset()] = 0x00;
+  ASSERT_EQ(0U, debug_malloc_usable_size(pointer));
+  ASSERT_TRUE(debug_realloc(pointer, 200) == nullptr);
+  debug_free(pointer);
+
+  // Fix the pointer and really free it.
+  pointer[-get_tag_offset()] = saved;
+  debug_free(pointer);
+
+  std::string expected_log(DIVIDER);
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ ALLOCATION %p HAS INVALID TAG 1ee7d000 (malloc_usable_size)\n",
+      pointer);
+  expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+  expected_log += "6 malloc_debug   #00 pc 0xa\n";
+  expected_log += "6 malloc_debug   #01 pc 0xb\n";
+  expected_log += "6 malloc_debug   #02 pc 0xc\n";
+  expected_log += DIVIDER;
+
+  expected_log += DIVIDER;
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ ALLOCATION %p HAS INVALID TAG 1ee7d000 (realloc)\n",
+      pointer);
+  expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+  expected_log += "6 malloc_debug   #00 pc 0xaa\n";
+  expected_log += "6 malloc_debug   #01 pc 0xbb\n";
+  expected_log += "6 malloc_debug   #02 pc 0xcc\n";
+  expected_log += DIVIDER;
+
+  expected_log += DIVIDER;
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ ALLOCATION %p HAS INVALID TAG 1ee7d000 (free)\n",
+      pointer);
+  expected_log += "6 malloc_debug Backtrace at time of failure:\n";
+  expected_log += "6 malloc_debug   #00 pc 0xaaa\n";
+  expected_log += "6 malloc_debug   #01 pc 0xbbb\n";
+  expected_log += "6 malloc_debug   #02 pc 0xccc\n";
+  expected_log += DIVIDER;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, leak_track_no_frees) {
+  Init("leak_track");
+
+  void* pointer1 = debug_malloc(200);
+  ASSERT_TRUE(pointer1 != nullptr);
+  memset(pointer1, 0, 200);
+
+  void* pointer2 = debug_malloc(128);
+  ASSERT_TRUE(pointer2 != nullptr);
+  memset(pointer2, 0, 128);
+
+  void* pointer3 = debug_malloc(1024);
+  ASSERT_TRUE(pointer3 != nullptr);
+  memset(pointer3, 0, 1024);
+
+  debug_finalize();
+  initialized = false;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log = android::base::StringPrintf(
+        "6 malloc_debug +++ malloc_testing leaked block of size 1024 at %p (leak 1 of 3)\n",
+      pointer3);
+  expected_log += android::base::StringPrintf(
+        "6 malloc_debug +++ malloc_testing leaked block of size 200 at %p (leak 2 of 3)\n",
+      pointer1);
+  expected_log += android::base::StringPrintf(
+        "6 malloc_debug +++ malloc_testing leaked block of size 128 at %p (leak 3 of 3)\n",
+      pointer2);
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, leak_track_no_frees_with_backtrace) {
+  Init("leak_track backtrace");
+
+  backtrace_fake_add(std::vector<uintptr_t> {0x1000, 0x2000, 0x3000});
+
+  void* pointer1 = debug_malloc(100);
+  ASSERT_TRUE(pointer1 != nullptr);
+  memset(pointer1, 0, 100);
+
+  backtrace_fake_add(std::vector<uintptr_t> {0xa000, 0xb000, 0xc000, 0xd000});
+
+  void* pointer2 = debug_malloc(128);
+  ASSERT_TRUE(pointer2 != nullptr);
+  memset(pointer2, 0, 128);
+
+  backtrace_fake_add(std::vector<uintptr_t> {0xfe000, 0xde000, 0xce000, 0xbe000, 0xae000});
+
+  void* pointer3 = debug_malloc(1024);
+  ASSERT_TRUE(pointer3 != nullptr);
+  memset(pointer3, 0, 1024);
+
+  debug_finalize();
+  initialized = false;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log = android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 1024 at %p (leak 1 of 3)\n",
+      pointer3);
+  expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
+  expected_log += "6 malloc_debug   #00 pc 0xfe000\n";
+  expected_log += "6 malloc_debug   #01 pc 0xde000\n";
+  expected_log += "6 malloc_debug   #02 pc 0xce000\n";
+  expected_log += "6 malloc_debug   #03 pc 0xbe000\n";
+  expected_log += "6 malloc_debug   #04 pc 0xae000\n";
+
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 128 at %p (leak 2 of 3)\n",
+      pointer2);
+  expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
+  expected_log += "6 malloc_debug   #00 pc 0xa000\n";
+  expected_log += "6 malloc_debug   #01 pc 0xb000\n";
+  expected_log += "6 malloc_debug   #02 pc 0xc000\n";
+  expected_log += "6 malloc_debug   #03 pc 0xd000\n";
+
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 100 at %p (leak 3 of 3)\n",
+      pointer1);
+  expected_log += "6 malloc_debug Backtrace at time of allocation:\n";
+  expected_log += "6 malloc_debug   #00 pc 0x1000\n";
+  expected_log += "6 malloc_debug   #01 pc 0x2000\n";
+  expected_log += "6 malloc_debug   #02 pc 0x3000\n";
+
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, leak_track_frees) {
+  Init("leak_track");
+
+  void* pointer1 = debug_malloc(390);
+  ASSERT_TRUE(pointer1 != nullptr);
+  memset(pointer1, 0, 390);
+  debug_free(pointer1);
+
+  pointer1 = debug_malloc(100);
+  ASSERT_TRUE(pointer1 != nullptr);
+  memset(pointer1, 0, 100);
+
+  void* pointer2 = debug_malloc(250);
+  ASSERT_TRUE(pointer2 != nullptr);
+  memset(pointer2, 0, 250);
+  debug_free(pointer2);
+
+  pointer2 = debug_malloc(450);
+  ASSERT_TRUE(pointer2 != nullptr);
+  memset(pointer2, 0, 450);
+
+  void* pointer3 = debug_malloc(999);
+  ASSERT_TRUE(pointer3 != nullptr);
+  memset(pointer3, 0, 999);
+  debug_free(pointer2);
+
+  debug_finalize();
+  initialized = false;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log = android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 999 at %p (leak 1 of 2)\n",
+      pointer3);
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 100 at %p (leak 2 of 2)\n",
+      pointer1);
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, free_track) {
+  Init("free_track=5");
+
+  void* pointers[10];
+  for (size_t i = 0; i < sizeof(pointers) / sizeof(void*); i++) {
+    pointers[i] = debug_malloc(100 + i);
+    ASSERT_TRUE(pointers[i] != nullptr);
+    memset(pointers[i], 0, 100 + i);
+    debug_free(pointers[i]);
+  }
+
+  // Large allocations (> 4096) to verify large allocation checks.
+  void* pointer = debug_malloc(8192);
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 8192);
+  debug_free(pointer);
+
+  pointer = debug_malloc(9000);
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 9000);
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, free_track_use_after_free) {
+  Init("free_track=5");
+
+  uint8_t* pointers[5];
+  for (size_t i = 0; i < sizeof(pointers) / sizeof(void*); i++) {
+    pointers[i] = reinterpret_cast<uint8_t*>(debug_malloc(100 + i));
+    ASSERT_TRUE(pointers[i] != nullptr);
+    memset(pointers[i], 0, 100 + i);
+    debug_free(pointers[i]);
+  }
+
+  // Stomp on the data.
+  pointers[0][20] = 0xaf;
+  pointers[0][99] = 0x12;
+
+  pointers[3][3] = 0x34;
+
+  // Large allocations (> 4096) to verify large allocation checks.
+  uint8_t* pointer1_large = reinterpret_cast<uint8_t*>(debug_malloc(8192));
+  ASSERT_TRUE(pointer1_large != nullptr);
+  memset(pointer1_large, 0, 8192);
+  debug_free(pointer1_large);
+
+  pointer1_large[4095] = 0x90;
+  pointer1_large[4100] = 0x56;
+  pointer1_large[8191] = 0x89;
+
+  uint8_t* pointer2_large = reinterpret_cast<uint8_t*>(debug_malloc(9000));
+  ASSERT_TRUE(pointer2_large != nullptr);
+  memset(pointer2_large, 0, 9000);
+  debug_free(pointer2_large);
+
+  pointer2_large[8200] = 0x78;
+
+  // Do a bunch of alloc and free to verify the above frees are checked.
+  for (size_t i = 0; i < 10; i++) {
+    void* flush_pointer = debug_malloc(100+i);
+    ASSERT_TRUE(flush_pointer != nullptr);
+    memset(flush_pointer, 0, 100 + i);
+    debug_free(flush_pointer);
+  }
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log(DIVIDER);
+  expected_log += android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p USED AFTER FREE\n", pointers[0]);
+  expected_log += "6 malloc_debug   pointer[20] = 0xaf (expected 0xef)\n";
+  expected_log += "6 malloc_debug   pointer[99] = 0x12 (expected 0xef)\n";
+  expected_log += DIVIDER;
+  expected_log += DIVIDER;
+  expected_log += android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p USED AFTER FREE\n", pointers[3]);
+  expected_log += "6 malloc_debug   pointer[3] = 0x34 (expected 0xef)\n";
+  expected_log += DIVIDER;
+  expected_log += DIVIDER;
+  expected_log += android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p USED AFTER FREE\n", pointer1_large);
+  expected_log += "6 malloc_debug   pointer[4095] = 0x90 (expected 0xef)\n";
+  expected_log += "6 malloc_debug   pointer[4100] = 0x56 (expected 0xef)\n";
+  expected_log += "6 malloc_debug   pointer[8191] = 0x89 (expected 0xef)\n";
+  expected_log += DIVIDER;
+  expected_log += DIVIDER;
+  expected_log += android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p USED AFTER FREE\n", pointer2_large);
+  expected_log += "6 malloc_debug   pointer[8200] = 0x78 (expected 0xef)\n";
+  expected_log += DIVIDER;
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, free_track_use_after_free_finalize) {
+  Init("free_track=100");
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 100);
+  debug_free(pointer);
+
+  pointer[56] = 0x91;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+
+  debug_finalize();
+  initialized = false;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log(DIVIDER);
+  expected_log += android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p USED AFTER FREE\n", pointer);
+  expected_log += "6 malloc_debug   pointer[56] = 0x91 (expected 0xef)\n";
+  expected_log += DIVIDER;
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, free_track_use_after_free_with_backtrace) {
+  Init("free_track=100 backtrace");
+
+  // Alloc backtrace.
+  backtrace_fake_add(std::vector<uintptr_t> {0xf0, 0xe, 0xd});
+  // Free backtrace.
+  backtrace_fake_add(std::vector<uintptr_t> {0xfa, 0xeb, 0xdc});
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(200));
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 200);
+  debug_free(pointer);
+
+  pointer[101] = 0xab;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+
+  debug_finalize();
+  initialized = false;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log(DIVIDER);
+  expected_log += android::base::StringPrintf("6 malloc_debug +++ ALLOCATION %p USED AFTER FREE\n", pointer);
+  expected_log += "6 malloc_debug   pointer[101] = 0xab (expected 0xef)\n";
+  expected_log += "6 malloc_debug Backtrace at time of free:\n";
+  expected_log += "6 malloc_debug   #00 pc 0xfa\n";
+  expected_log += "6 malloc_debug   #01 pc 0xeb\n";
+  expected_log += "6 malloc_debug   #02 pc 0xdc\n";
+  expected_log += DIVIDER;
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, get_malloc_leak_info_invalid) {
+  Init("fill");
+
+  uint8_t* info;
+  size_t overall_size;
+  size_t info_size;
+  size_t total_memory;
+  size_t backtrace_size;
+
+  std::string expected_log("6 malloc_debug get_malloc_leak_info: At least one invalid parameter.\n");
+
+  debug_get_malloc_leak_info(nullptr, &overall_size, &info_size, &total_memory, &backtrace_size);
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+
+  resetLogs();
+  debug_get_malloc_leak_info(&info, nullptr, &info_size, &total_memory, &backtrace_size);
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+
+  resetLogs();
+  debug_get_malloc_leak_info(&info, &overall_size, nullptr, &total_memory, &backtrace_size);
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+
+  resetLogs();
+  debug_get_malloc_leak_info(&info, &overall_size, &info_size, nullptr, &backtrace_size);
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+
+  resetLogs();
+  debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, nullptr);
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, get_malloc_leak_info_not_enabled) {
+  Init("fill");
+
+  uint8_t* info;
+  size_t overall_size;
+  size_t info_size;
+  size_t total_memory;
+  size_t backtrace_size;
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+  std::string expected_log(
+      "6 malloc_debug get_malloc_leak_info: Allocations not being tracked, to enable "
+      "set the option 'backtrace'.\n");
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+struct InfoEntry {
+  size_t size;
+  size_t num_frames;
+  uintptr_t frames[0];
+} __attribute__((packed));
+
+TEST_F(MallocDebugTest, get_malloc_leak_info_empty) {
+  Init("backtrace");
+
+  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(0U, overall_size);
+  ASSERT_EQ(0U, info_size);
+  ASSERT_EQ(0U, total_memory);
+  ASSERT_EQ(0U, backtrace_size);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, get_malloc_leak_info_single) {
+  Init("backtrace");
+
+  // 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);
+  memset(expected_info.data(), 0, individual_size);
+
+  InfoEntry* entry = reinterpret_cast<InfoEntry*>(expected_info.data());
+  entry->size = 200;
+  entry->num_frames = 3;
+  entry->frames[0] = 0xf;
+  entry->frames[1] = 0xe;
+  entry->frames[2] = 0xd;
+
+  backtrace_fake_add(std::vector<uintptr_t> {0xf, 0xe, 0xd});
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(entry->size));
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, entry->size);
+
+  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, overall_size);
+  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);
+
+  debug_free_malloc_leak_info(info);
+
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, get_malloc_leak_info_multi) {
+  Init("backtrace=16");
+
+  // 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 * 3);
+  memset(expected_info.data(), 0, individual_size * 3);
+
+  InfoEntry* entry0 = reinterpret_cast<InfoEntry*>(expected_info.data());
+  InfoEntry* entry1 = reinterpret_cast<InfoEntry*>(
+      reinterpret_cast<uintptr_t>(entry0) + individual_size);
+  InfoEntry* entry2 = reinterpret_cast<InfoEntry*>(
+      reinterpret_cast<uintptr_t>(entry1) + individual_size);
+
+  // These values will be in the reverse order that we create.
+  entry2->size = 500;
+  entry2->num_frames = 4;
+  entry2->frames[0] = 0xf;
+  entry2->frames[1] = 0xe;
+  entry2->frames[2] = 0xd;
+  entry2->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(entry2->size));
+  ASSERT_TRUE(pointers[0] != nullptr);
+  memset(pointers[0], 0, entry2->size);
+
+  entry1->size = 4100;
+  entry1->num_frames = 16;
+  for (size_t i = 0; i < 16; i++) {
+    entry1->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(entry1->size));
+  ASSERT_TRUE(pointers[1] != nullptr);
+  memset(pointers[1], 0, entry1->size);
+
+  entry0->size = 9000;
+  entry0->num_frames = 1;
+
+  entry0->frames[0] = 0x104;
+  backtrace_fake_add(std::vector<uintptr_t> {0x104});
+
+  pointers[2] = reinterpret_cast<uint8_t*>(debug_malloc(entry0->size));
+  ASSERT_TRUE(pointers[2] != nullptr);
+  memset(pointers[2], 0, entry0->size);
+
+  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);
+  ASSERT_EQ(500U + 4100U + 9000U, total_memory);
+  ASSERT_EQ(16U, backtrace_size);
+  ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0);
+
+  debug_free_malloc_leak_info(info);
+
+  debug_free(pointers[0]);
+  debug_free(pointers[1]);
+  debug_free(pointers[2]);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, get_malloc_leak_info_multi_skip_empty_backtrace) {
+  Init("backtrace=16");
+
+  // 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_frames = 4;
+  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_frames = 16;
+  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);
+
+  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);
+  ASSERT_EQ(500U + 4100U, total_memory);
+  ASSERT_EQ(16U, backtrace_size);
+  ASSERT_TRUE(memcmp(expected_info.data(), info, overall_size) == 0);
+
+  debug_free_malloc_leak_info(info);
+
+  debug_free(pointers[0]);
+  debug_free(pointers[1]);
+  debug_free(pointers[2]);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, realloc_usable_size) {
+  Init("front_guard");
+
+  // Verify that if the usable size > size of alloc, that realloc
+  // copies the bytes in the usable size not just the size.
+  // This assumes that an allocation of size 1 returns usable size > 1.
+  // If this isn't true, this test is not going to do anything.
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(1));
+  ASSERT_TRUE(pointer != nullptr);
+  size_t usable_size = debug_malloc_usable_size(pointer);
+  memset(pointer, 0xaa, usable_size);
+  pointer = reinterpret_cast<uint8_t*>(debug_realloc(pointer, usable_size + 10));
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_LE(usable_size + 10, debug_malloc_usable_size(pointer));
+  for (size_t i = 0; i < usable_size; i++) {
+    ASSERT_EQ(0xaa, pointer[i]) << "Failed compare at byte " << i;
+  }
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+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);
+
+  backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xecd00, 0x12000});
+  backtrace_fake_add(std::vector<uintptr_t> {0x100, 0x200, 0x300, 0x400});
+  backtrace_fake_add(std::vector<uintptr_t> {0x500, 0xa00, 0xb00});
+
+  // First allocation should not actually attempt to get the backtrace.
+  void* pointer = debug_malloc(10);
+  ASSERT_TRUE(pointer != 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(0U, overall_size);
+  ASSERT_EQ(0U, info_size);
+  ASSERT_EQ(0U, total_memory);
+  ASSERT_EQ(0U, backtrace_size);
+  debug_free(pointer);
+
+  debug_free_malloc_leak_info(info);
+
+  // Send the signal to enable.
+  ASSERT_TRUE(kill(getpid(), SIGRTMIN + 10) == 0);
+  sleep(1);
+
+  pointer = debug_malloc(100);
+  ASSERT_TRUE(pointer != nullptr);
+
+  debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+  ASSERT_TRUE(info != nullptr);
+  ASSERT_EQ(individual_size, overall_size);
+  ASSERT_EQ(individual_size, info_size);
+  ASSERT_EQ(100U, total_memory);
+  ASSERT_EQ(20U, backtrace_size);
+  uintptr_t* ips = reinterpret_cast<uintptr_t*>(&info[2 * sizeof(size_t)]);
+  ASSERT_EQ(0xbc000U, ips[0]);
+  ASSERT_EQ(0xecd00U, ips[1]);
+  ASSERT_EQ(0x12000U, ips[2]);
+  for (size_t i = 3; i < 20; i++) {
+    ASSERT_EQ(0U, ips[i]);
+  }
+
+  debug_free(pointer);
+
+  debug_free_malloc_leak_info(info);
+
+  // Send the signal to disable.
+  ASSERT_TRUE(kill(getpid(), SIGRTMIN + 10) == 0);
+  sleep(1);
+
+  pointer = debug_malloc(200);
+  ASSERT_TRUE(pointer != nullptr);
+
+  debug_get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+  ASSERT_TRUE(info == nullptr);
+  ASSERT_EQ(0U, overall_size);
+  ASSERT_EQ(0U, info_size);
+  ASSERT_EQ(0U, total_memory);
+  ASSERT_EQ(0U, backtrace_size);
+
+  debug_free(pointer);
+
+  debug_free_malloc_leak_info(info);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to enable backtracing.\n",
+      SIGRTMIN + 10, getpid());
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, overflow) {
+  Init("guard fill_on_free");
+
+  void* pointer = debug_malloc(SIZE_MAX);
+  ASSERT_TRUE(pointer == nullptr);
+  ASSERT_EQ(ENOMEM, errno);
+
+  pointer = debug_calloc(1, SIZE_MAX);
+  ASSERT_TRUE(pointer == nullptr);
+  ASSERT_EQ(ENOMEM, errno);
+
+  pointer = debug_calloc(SIZE_MAX, 1);
+  ASSERT_TRUE(pointer == nullptr);
+  ASSERT_EQ(ENOMEM, errno);
+
+  pointer = debug_calloc(SIZE_MAX/100, 100);
+  ASSERT_TRUE(pointer == nullptr);
+  ASSERT_EQ(ENOMEM, errno);
+
+  pointer = debug_calloc(100, SIZE_MAX/100);
+  ASSERT_TRUE(pointer == nullptr);
+  ASSERT_EQ(ENOMEM, errno);
+
+  pointer = debug_realloc(nullptr, SIZE_MAX);
+  ASSERT_TRUE(pointer == nullptr);
+  ASSERT_EQ(ENOMEM, errno);
+
+  pointer = debug_malloc(100);
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0xd0, 100);
+
+  void* realloc_pointer = debug_realloc(pointer, SIZE_MAX);
+  ASSERT_TRUE(realloc_pointer == nullptr);
+  // Verify the pointer was not freed.
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(0xd0, reinterpret_cast<uint8_t*>(pointer)[i]) << "Failed checking byte " << i;
+  }
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+static void VerifyZygoteSet(size_t memory_bytes) {
+  size_t expected_info_size = 2 * sizeof(size_t) + 16 * sizeof(uintptr_t);
+  std::vector<uint8_t> expected_info(expected_info_size);
+  memset(expected_info.data(), 0, expected_info_size);
+  InfoEntry* entry = reinterpret_cast<InfoEntry*>(expected_info.data());
+  entry->size = memory_bytes | (1U << 31);
+  entry->num_frames = 1;
+  entry->frames[0] = 0x1;
+
+  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_EQ(expected_info_size, overall_size);
+  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);
+
+  debug_free_malloc_leak_info(info);
+}
+
+TEST_F(MallocDebugTest, zygote_set) {
+  // Set all of the options.
+  Init("guard fill backtrace leak_track free_track=2");
+
+  zygote = 1;
+
+  backtrace_fake_add(std::vector<uintptr_t> {0x1});
+
+  void* pointer = debug_malloc(100);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_EQ(100U, debug_malloc_usable_size(pointer));
+  memset(pointer, 0, 100);
+  VerifyZygoteSet(100);
+  debug_free(pointer);
+
+  backtrace_fake_add(std::vector<uintptr_t> {0x1});
+  pointer = debug_calloc(10, 20);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_EQ(200U, debug_malloc_usable_size(pointer));
+  VerifyZygoteSet(200);
+  debug_free(pointer);
+
+  backtrace_fake_add(std::vector<uintptr_t> {0x1});
+  pointer = debug_memalign(128, 300);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_EQ(300U, debug_malloc_usable_size(pointer));
+  memset(pointer, 0, 300);
+  VerifyZygoteSet(300);
+  debug_free(pointer);
+
+  backtrace_fake_add(std::vector<uintptr_t> {0x1});
+  pointer = debug_malloc(500);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_EQ(500U, debug_malloc_usable_size(pointer));
+  memset(pointer, 0, 500);
+  VerifyZygoteSet(500);
+
+  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);
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, max_size) {
+  Init("guard");
+
+  void* pointer = debug_malloc(1U << 31);
+  ASSERT_TRUE(pointer == nullptr);
+
+  pointer = debug_calloc(1, 1U << 31);
+  ASSERT_TRUE(pointer == nullptr);
+
+  pointer = debug_calloc(1U << 31, 1);
+  ASSERT_TRUE(pointer == nullptr);
+
+  pointer = debug_memalign(16, 1U << 31);
+  ASSERT_TRUE(pointer == nullptr);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, debug_mallinfo) {
+  Init("guard");
+
+  void* pointer = debug_malloc(150);
+  ASSERT_TRUE(pointer != nullptr);
+
+  struct mallinfo mi = debug_mallinfo();
+  EXPECT_NE(0U, mi.uordblks);
+
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, debug_posix_memalign) {
+  Init("guard");
+
+  void* pointer;
+  ASSERT_EQ(0, debug_posix_memalign(&pointer, 32, 300));
+  ASSERT_TRUE(pointer != nullptr);
+  debug_free(pointer);
+
+  ASSERT_EQ(EINVAL, debug_posix_memalign(&pointer, 11, 300));
+
+  ASSERT_EQ(ENOMEM, debug_posix_memalign(&pointer, 16, SIZE_MAX));
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+TEST_F(MallocDebugTest, debug_pvalloc) {
+  Init("guard");
+
+  size_t pagesize = getpagesize();
+  void* pointer = debug_pvalloc(1);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_EQ(pagesize, debug_malloc_usable_size(pointer));
+  uintptr_t value = reinterpret_cast<uintptr_t>(pointer) & (pagesize - 1);
+  ASSERT_EQ(0U, value);
+  debug_free(pointer);
+}
+
+TEST_F(MallocDebugTest, debug_valloc) {
+  Init("guard");
+
+  size_t pagesize = getpagesize();
+  void* pointer = debug_valloc(100);
+  ASSERT_TRUE(pointer != nullptr);
+  ASSERT_EQ(100U, debug_malloc_usable_size(pointer));
+  uintptr_t value = reinterpret_cast<uintptr_t>(pointer) & (pagesize - 1);
+  ASSERT_EQ(0U, value);
+  debug_free(pointer);
+}
+#endif
diff --git a/libc/malloc_debug/tests/property_fake.cpp b/libc/malloc_debug/tests/property_fake.cpp
new file mode 100644
index 0000000..d9f0ad8
--- /dev/null
+++ b/libc/malloc_debug/tests/property_fake.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+
+#include <string>
+#include <unordered_map>
+
+#include <sys/system_properties.h>
+
+std::unordered_map<std::string, std::string> g_properties;
+
+extern "C" int property_set(const char* name, const char* value) {
+  if (g_properties.count(name) != 0) {
+    g_properties.erase(name);
+  }
+  g_properties[name] = value;
+  return 0;
+}
+
+extern "C" int property_get(const char* key, char* value, const char* default_value) {
+  if (g_properties.count(key) == 0) {
+    if (default_value == nullptr) {
+      return 0;
+    }
+    strncpy(value, default_value, PROP_VALUE_MAX-1);
+  } else {
+    strncpy(value, g_properties[key].c_str(), PROP_VALUE_MAX-1);
+  }
+  value[PROP_VALUE_MAX-1] = '\0';
+  return strlen(value);
+}
+
+extern "C" int __system_property_get(const char* key, char* value) {
+  if (g_properties.count(key) == 0) {
+    return 0;
+  } else {
+    strncpy(value, g_properties[key].c_str(), PROP_VALUE_MAX-1);
+  }
+  value[PROP_VALUE_MAX-1] = '\0';
+  return strlen(value);
+}