Merge "Fix it to call the lambda function"
diff --git a/README.md b/README.md
index e67f305..85c8190 100644
--- a/README.md
+++ b/README.md
@@ -211,6 +211,10 @@
      implemented in the kernel. For simple syscalls, that's just the
      auto-generated argument and return value marshalling.
 
+     Add a test in the right file in tests/. We have one file per header, so if
+     your system call is exposed in <unistd.h>, for example, your test would go
+     in tests/unistd_test.cpp.
+
      A trivial test that deliberately supplies an invalid argument helps check
      that we're generating the right symbol and have the right declaration in
      the header file, and that the change to libc.map.txt from step 5 is
@@ -237,6 +241,39 @@
 than 2GiB, say -- so you may end up just writing a "meaningless" program whose
 only purpose is to give you patterns to look for when run under strace(1).)
 
+A general example of adding a system call:
+https://android-review.googlesource.com/c/platform/bionic/+/2073827
+
+### Debugging tips
+1. Key error for a new codename in libc/libc.map.txt
+e.g. what you add in libc/libc.map.txt is:
+
+```
+LIBC_V { # introduced=Vanilla
+  global:
+    xxx; // the new system call you add
+} LIBC_U;
+```
+
+The error output is:
+
+```
+Traceback (most recent call last):
+  File "/path/tp/out/soong/.temp/Soong.python_qucjwd7g/symbolfile/__init__.py", line 171,
+  in decode_api_level_tag
+    decoded = str(decode_api_level(value, api_map))
+  File "/path/to/out/soong/.temp/Soong.python_qucjwd7g/symbolfile/__init__.py", line 157,
+  in decode_api_level
+    return api_map[api]
+KeyError: 'Vanilla'
+```
+
+Solution: Ask in the team and wait for the update.
+
+2. Use of undeclared identifier of the new system call in the test
+Possible Solution: Check everything ready in the files mentioned above first.
+Maybe glibc matters. Follow the example and try #if defined(__GLIBC__).
+
 ## Updating kernel header files
 
 As mentioned above, this is currently a two-step process:
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 1435e79..45b2a1b 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -108,6 +108,7 @@
 
 int         __close:close(int)  all
 int         close_range(unsigned int, unsigned int, int) all
+ssize_t     copy_file_range(int, off64_t*, int, off64_t*, size_t, unsigned int) all
 pid_t       __getpid:getpid()  all
 int memfd_create(const char*, unsigned) all
 int         munmap(void*, size_t)  all
diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp
index 41aa205..9b67d85 100644
--- a/libc/bionic/heap_tagging.cpp
+++ b/libc/bionic/heap_tagging.cpp
@@ -72,33 +72,26 @@
 }
 
 static bool set_tcf_on_all_threads(int tcf) {
-  static int g_tcf;
-  g_tcf = tcf;
-
   return android_run_on_all_threads(
-      [](void*) {
+      [](void* arg) {
+        int tcf = *reinterpret_cast<int*>(arg);
         int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
         if (tagged_addr_ctrl < 0) {
           return false;
         }
 
-        tagged_addr_ctrl = (tagged_addr_ctrl & ~PR_MTE_TCF_MASK) | g_tcf;
+        tagged_addr_ctrl = (tagged_addr_ctrl & ~PR_MTE_TCF_MASK) | tcf;
         if (prctl(PR_SET_TAGGED_ADDR_CTRL, tagged_addr_ctrl, 0, 0, 0) < 0) {
           return false;
         }
         return true;
       },
-      nullptr);
+      &tcf);
 }
 
 pthread_mutex_t g_heap_tagging_lock = PTHREAD_MUTEX_INITIALIZER;
 
 // Requires `g_heap_tagging_lock` to be held.
-HeapTaggingLevel GetHeapTaggingLevel() {
-  return heap_tagging_level;
-}
-
-// Requires `g_heap_tagging_lock` to be held.
 bool SetHeapTaggingLevel(HeapTaggingLevel tag_level) {
   if (tag_level == heap_tagging_level) {
     return true;
diff --git a/libc/bionic/heap_tagging.h b/libc/bionic/heap_tagging.h
index 110b6ed..a3588b8 100644
--- a/libc/bionic/heap_tagging.h
+++ b/libc/bionic/heap_tagging.h
@@ -40,7 +40,6 @@
 // useful for RAII on this lock.
 extern pthread_mutex_t g_heap_tagging_lock;
 
-// These functions can be called in a multithreaded context, and thus should
+// This function can be called in a multithreaded context, and thus should
 // only be called when holding the `g_heap_tagging_lock`.
 bool SetHeapTaggingLevel(HeapTaggingLevel level);
-HeapTaggingLevel GetHeapTaggingLevel();
diff --git a/libc/bionic/mmap.cpp b/libc/bionic/mmap.cpp
index 9aad0b3..ed6b9c6 100644
--- a/libc/bionic/mmap.cpp
+++ b/libc/bionic/mmap.cpp
@@ -39,37 +39,20 @@
 
 #define MMAP2_SHIFT 12 // 2**12 == 4096
 
-static bool kernel_has_MADV_MERGEABLE = true;
-
 void* mmap64(void* addr, size_t size, int prot, int flags, int fd, off64_t offset) {
   if (offset < 0 || (offset & ((1UL << MMAP2_SHIFT)-1)) != 0) {
     errno = EINVAL;
     return MAP_FAILED;
   }
 
-  // prevent allocations large enough for `end - start` to overflow
+  // Prevent allocations large enough for `end - start` to overflow.
   size_t rounded = __BIONIC_ALIGN(size, PAGE_SIZE);
   if (rounded < size || rounded > PTRDIFF_MAX) {
     errno = ENOMEM;
     return MAP_FAILED;
   }
 
-  bool is_private_anonymous =
-      (flags & (MAP_PRIVATE | MAP_ANONYMOUS)) == (MAP_PRIVATE | MAP_ANONYMOUS);
-  bool is_stack_or_grows_down = (flags & (MAP_STACK | MAP_GROWSDOWN)) != 0;
-
-  void* result = __mmap2(addr, size, prot, flags, fd, offset >> MMAP2_SHIFT);
-
-  if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE &&
-      is_private_anonymous && !is_stack_or_grows_down) {
-    ErrnoRestorer errno_restorer;
-    int rc = madvise(result, size, MADV_MERGEABLE);
-    if (rc == -1 && errno == EINVAL) {
-      kernel_has_MADV_MERGEABLE = false;
-    }
-  }
-
-  return result;
+  return __mmap2(addr, size, prot, flags, fd, offset >> MMAP2_SHIFT);
 }
 
 void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset) {
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index f142525..b5694b8 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -313,6 +313,17 @@
 int getdomainname(char* __buf, size_t __buf_size) __INTRODUCED_IN(26);
 int setdomainname(const char* __name, size_t __n) __INTRODUCED_IN(26);
 
+/**
+ * [copy_file_range(2)](https://man7.org/linux/man-pages/man2/copy_file_range.2.html) copies
+ * a range of data from one file descriptor to another.
+ *
+ * Returns the number of bytes copied on success, and returns -1 and sets  errno
+ * on failure.
+ *
+ * Available since API level 34.
+ */
+ssize_t copy_file_range(int __fd_in, off64_t* __off_in, int __fd_out, off64_t* __off_out, size_t __length, unsigned int __flags) __INTRODUCED_IN(34);
+
 #if __ANDROID_API__ >= 28
 void swab(const void* __src, void* __dst, ssize_t __byte_count) __INTRODUCED_IN(28);
 #endif
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index e64fe00..79f331a 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1579,6 +1579,7 @@
 LIBC_U { # introduced=UpsideDownCake
   global:
     close_range;
+    copy_file_range;
 } LIBC_T;
 
 LIBC_PRIVATE {
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index 7ff3db2..e7a157e 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -64,6 +64,7 @@
         "malloc_debug.cpp",
         "PointerData.cpp",
         "RecordData.cpp",
+        "Unreachable.cpp",
         "UnwindBacktrace.cpp",
     ],
 
@@ -73,6 +74,7 @@
         "libasync_safe",
         "libbase",
         "libc_malloc_debug_backtrace",
+        "libmemunreachable",
     ],
 
     shared_libs: [
@@ -120,6 +122,7 @@
 cc_test {
     name: "malloc_debug_unit_tests",
     test_suites: ["device-tests"],
+    isolated: true,
 
     srcs: [
         "tests/backtrace_fake.cpp",
@@ -179,7 +182,6 @@
 
     shared_libs: [
         "libbase",
-        "libbacktrace",
         "liblog",
         "libunwindstack",
     ],
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index 11887e2..6a81277 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -70,17 +70,34 @@
 
 const std::unordered_map<std::string, Config::OptionInfo> Config::kOptions = {
     {
-        "guard", {FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, &Config::SetGuard},
+        "guard",
+        {FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, &Config::SetGuard},
     },
     {
-        "front_guard", {FRONT_GUARD | TRACK_ALLOCS, &Config::SetFrontGuard},
+        "front_guard",
+        {FRONT_GUARD | TRACK_ALLOCS, &Config::SetFrontGuard},
     },
     {
-        "rear_guard", {REAR_GUARD | TRACK_ALLOCS, &Config::SetRearGuard},
+        "rear_guard",
+        {REAR_GUARD | TRACK_ALLOCS, &Config::SetRearGuard},
     },
 
     {
-        "backtrace", {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
+        "backtrace_size",
+        {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceSize},
+    },
+    {
+        "backtrace_min_size",
+        {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMinSize},
+    },
+    {
+        "backtrace_max_size",
+        {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMaxSize},
+    },
+
+    {
+        "backtrace",
+        {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
     },
     {
         "backtrace_enable_on_signal",
@@ -88,55 +105,74 @@
     },
 
     {
-        "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},
     },
     {
-        "backtrace_full", {BACKTRACE_FULL, &Config::VerifyValueEmpty},
+        "backtrace_full",
+        {BACKTRACE_FULL, &Config::VerifyValueEmpty},
     },
 
     {
-        "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 | TRACK_ALLOCS, &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},
+        "verify_pointers",
+        {TRACK_ALLOCS, &Config::VerifyValueEmpty},
     },
     {
-        "abort_on_error", {ABORT_ON_ERROR, &Config::VerifyValueEmpty},
+        "abort_on_error",
+        {ABORT_ON_ERROR, &Config::VerifyValueEmpty},
     },
     {
-        "verbose", {VERBOSE, &Config::VerifyValueEmpty},
+        "verbose",
+        {VERBOSE, &Config::VerifyValueEmpty},
+    },
+    {
+        "check_unreachable_on_signal",
+        {CHECK_UNREACHABLE_ON_SIGNAL, &Config::VerifyValueEmpty},
     },
 };
 
@@ -274,6 +310,23 @@
   return true;
 }
 
+bool Config::SetBacktraceSize(const std::string& option, const std::string& value) {
+  if (!ParseValue(option, value, 1, SIZE_MAX, &backtrace_min_size_bytes_)) {
+    return false;
+  }
+  backtrace_max_size_bytes_ = backtrace_min_size_bytes_;
+
+  return true;
+}
+
+bool Config::SetBacktraceMinSize(const std::string& option, const std::string& value) {
+  return ParseValue(option, value, 1, SIZE_MAX, &backtrace_min_size_bytes_);
+}
+
+bool Config::SetBacktraceMaxSize(const std::string& option, const std::string& value) {
+  return ParseValue(option, value, 1, SIZE_MAX, &backtrace_max_size_bytes_);
+}
+
 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_);
 }
@@ -380,6 +433,9 @@
   backtrace_enabled_ = false;
   backtrace_dump_on_exit_ = false;
   backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX;
+  backtrace_min_size_bytes_ = 0;
+  backtrace_max_size_bytes_ = SIZE_MAX;
+  check_unreachable_signal_ = SIGRTMAX - 16;
 
   // Process each option name we can find.
   std::string option;
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index 1b5c748..ef1d2a9 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -46,6 +46,8 @@
 constexpr uint64_t BACKTRACE_FULL = 0x400;
 constexpr uint64_t ABORT_ON_ERROR = 0x800;
 constexpr uint64_t VERBOSE = 0x1000;
+constexpr uint64_t CHECK_UNREACHABLE_ON_SIGNAL = 0x2000;
+constexpr uint64_t BACKTRACE_SPECIFIC_SIZES = 0x4000;
 
 // In order to guarantee posix compliance, set the minimum alignment
 // to 8 bytes for 32 bit systems and 16 bytes for 64 bit systems.
@@ -89,10 +91,15 @@
   uint8_t fill_alloc_value() const { return fill_alloc_value_; }
   uint8_t fill_free_value() const { return fill_free_value_; }
 
+  size_t backtrace_min_size_bytes() const { return backtrace_min_size_bytes_; }
+  size_t backtrace_max_size_bytes() const { return backtrace_max_size_bytes_; }
+
   int record_allocs_signal() const { return record_allocs_signal_; }
   size_t record_allocs_num_entries() const { return record_allocs_num_entries_; }
   const std::string& record_allocs_file() const { return record_allocs_file_; }
 
+  int check_unreachable_signal() const { return check_unreachable_signal_; }
+
  private:
   struct OptionInfo {
     uint64_t option;
@@ -118,6 +125,10 @@
   bool SetBacktraceDumpOnExit(const std::string& option, const std::string& value);
   bool SetBacktraceDumpPrefix(const std::string& option, const std::string& value);
 
+  bool SetBacktraceSize(const std::string& option, const std::string& value);
+  bool SetBacktraceMinSize(const std::string& option, const std::string& value);
+  bool SetBacktraceMaxSize(const std::string& option, const std::string& value);
+
   bool SetExpandAlloc(const std::string& option, const std::string& value);
 
   bool SetFreeTrack(const std::string& option, const std::string& value);
@@ -142,6 +153,8 @@
   size_t backtrace_frames_ = 0;
   bool backtrace_dump_on_exit_ = false;
   std::string backtrace_dump_prefix_;
+  size_t backtrace_min_size_bytes_ = 0;
+  size_t backtrace_max_size_bytes_ = 0;
 
   size_t fill_on_alloc_bytes_ = 0;
   size_t fill_on_free_bytes_ = 0;
@@ -160,4 +173,6 @@
   uint8_t fill_free_value_;
   uint8_t front_guard_value_;
   uint8_t rear_guard_value_;
+
+  int check_unreachable_signal_ = 0;
 };
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
index eaa0eb7..5ab2232 100644
--- a/libc/malloc_debug/PointerData.cpp
+++ b/libc/malloc_debug/PointerData.cpp
@@ -136,7 +136,22 @@
   return true;
 }
 
-size_t PointerData::AddBacktrace(size_t num_frames) {
+static inline bool ShouldBacktraceAllocSize(size_t size_bytes) {
+  static bool only_backtrace_specific_sizes =
+      g_debug->config().options() & BACKTRACE_SPECIFIC_SIZES;
+  if (!only_backtrace_specific_sizes) {
+    return true;
+  }
+  static size_t min_size_bytes = g_debug->config().backtrace_min_size_bytes();
+  static size_t max_size_bytes = g_debug->config().backtrace_max_size_bytes();
+  return size_bytes >= min_size_bytes && size_bytes <= max_size_bytes;
+}
+
+size_t PointerData::AddBacktrace(size_t num_frames, size_t size_bytes) {
+  if (!ShouldBacktraceAllocSize(size_bytes)) {
+    return kBacktraceEmptyIndex;
+  }
+
   std::vector<uintptr_t> frames;
   std::vector<unwindstack::FrameData> frames_info;
   if (g_debug->config().options() & BACKTRACE_FULL) {
@@ -149,14 +164,14 @@
     if (num_frames == 0) {
       return kBacktraceEmptyIndex;
     }
+    frames.resize(num_frames);
   }
 
-  FrameKeyType key{.num_frames = num_frames, .frames = frames.data()};
+  FrameKeyType key{.num_frames = frames.size(), .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);
@@ -198,7 +213,7 @@
 void PointerData::Add(const void* ptr, size_t pointer_size) {
   size_t hash_index = 0;
   if (backtrace_enabled_) {
-    hash_index = AddBacktrace(g_debug->config().backtrace_frames());
+    hash_index = AddBacktrace(g_debug->config().backtrace_frames(), pointer_size);
   }
 
   std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
@@ -336,11 +351,11 @@
   }
 }
 
-void* PointerData::AddFreed(const void* ptr) {
+void* PointerData::AddFreed(const void* ptr, size_t size_bytes) {
   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);
+    hash_index = AddBacktrace(num_frames, size_bytes);
   }
 
   void* last = nullptr;
diff --git a/libc/malloc_debug/PointerData.h b/libc/malloc_debug/PointerData.h
index 97eec0a..3194bab 100644
--- a/libc/malloc_debug/PointerData.h
+++ b/libc/malloc_debug/PointerData.h
@@ -137,13 +137,13 @@
 
   static void IteratePointers(std::function<void(uintptr_t pointer)> fn);
 
-  static size_t AddBacktrace(size_t num_frames);
+  static size_t AddBacktrace(size_t num_frames, size_t size_bytes);
   static void RemoveBacktrace(size_t hash_index);
 
   static void Add(const void* pointer, size_t size);
   static void Remove(const void* pointer);
 
-  static void* AddFreed(const void* pointer);
+  static void* AddFreed(const void* pointer, size_t size_bytes);
   static void LogFreeError(const FreePointerInfoType& info, size_t usable_size);
   static void LogFreeBacktrace(const void* ptr);
   static void VerifyFreedPointer(const FreePointerInfoType& info);
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index 662f5f8..3667624 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -114,7 +114,7 @@
 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
+file when the process receives the signal SIGRTMAX - 17 ( which is 47 on
 Android devices). The format of this dumped data is the same format as
 that dumped when running am dumpheap -n. The default is to dump this data
 to the file /data/local/tmp/backtrace\_heap.**PID**.txt. This is useful when
@@ -127,7 +127,7 @@
 ### backtrace\_enable\_on\_signal[=MAX\_FRAMES]
 Enable capturing the backtrace of each allocation site. If the
 backtrace capture is toggled when the process receives the signal
-SIGRTMAX - 19 (which is 45 on most Android devices). When this
+SIGRTMAX - 19 (which is 45 on Android devices). When this
 option is used alone, backtrace capture starts out disabled until the signal
 is received. If both this option and the backtrace option are set, then
 backtrace capture is enabled until the signal is received.
@@ -160,11 +160,69 @@
 on the signal will be backtrace\_dump\_prefix.**PID**.txt. The filename chosen
 when the program exits will be backtrace\_dump\_prefix.**PID**.exit.txt.
 
+### backtrace\_min\_size=ALLOCATION\_SIZE\_BYTES
+As of U, setting this in combination with the backtrace option means
+that only allocations of a size greater than or equal to
+**ALLOCATION\_SIZE\_BYTES** will be backtraced. When used in combination
+with the backtrace\_max\_size option, then allocations greater than or
+equal to backtrace\_min\_size and less than or equal to
+backtrace\_max\_size will be backtraced. The backtrace\_size option
+overrides this option, and should not be used at the same time.
+
+This option can also be used in combination with other tools such
+as [libmemunreachable](https://android.googlesource.com/platform/system/memory/libmemunreachable/+/master/README.md)
+to only get backtraces for sizes of allocations listed as being leaked.
+
+### backtrace\_max\_size=ALLOCATION\_SIZE\_BYTES
+As of U, setting this in combination with the backtrace option means
+that only allocations of a size less than or equal to
+**ALLOCATION\_SIZE\_BYTES** will be backtraced. When used in combination
+with the backtrace\_min\_size option, then allocations greater than or
+equal to backtrace\_min\_size and less than or equal to
+backtrace\_max\_size will be backtraced. The backtrace\_size option
+overrides this option, and should not be used at the same time.
+
+This option can also be used in combination with other tools such
+as [libmemunreachable](https://android.googlesource.com/platform/system/memory/libmemunreachable/+/master/README.md)
+to only get backtraces for sizes of allocations listed as being leaked.
+
+### backtrace\_size=ALLOCATION\_SIZE\_BYTES
+As of U, setting this in combination with the backtrace option means
+that only allocations of size **ALLOCATION\_SIZE\_BYTES** will be backtraced.
+This option overrides the backtrace\_min\_size and the backtrace\_max\_size.
+
+This option can also be used in combination with other tools such
+as [libmemunreachable](https://android.googlesource.com/platform/system/memory/libmemunreachable/+/master/README.md)
+to only get backtraces for sizes of allocations listed as being leaked.
+
 ### backtrace\_full
 As of Q, any time that a backtrace is gathered, a different algorithm is used
 that is extra thorough and can unwind through Java frames. This will run
 slower than the normal backtracing function.
 
+### check\_unreachable\_on\_signal
+As of Android U, this option will trigger a check for unreachable memory
+in a process. Specifically, if the signal SIGRTMAX - 16 (which is 48 on
+Android devices). The best way to see the exact signal being used is to
+enable the verbose option then look at the log for the message:
+
+    Run: 'kill -48 <PID>' to check for unreachable memory.
+
+When the signal is received, the actual unreachable check only triggers
+on the next allocation that happens in the process (malloc/free, etc).
+
+If a process is not doing any allocations, it can be forced to trigger when
+running:
+
+    debuggerd -b <PID>
+
+**NOTE**: The unreachable check can fail for protected processes, so it
+might be necessary to run:
+
+    setenforce 0
+
+To get the unreachable data.
+
 ### fill\_on\_alloc[=MAX\_FILLED\_BYTES]
 Any allocation routine, other than calloc, will result in the allocation being
 filled with the value 0xeb. When doing a realloc to a larger size, the bytes
@@ -270,7 +328,7 @@
 
 ### record\_allocs[=TOTAL\_ENTRIES]
 Keep track of every allocation/free made on every thread and dump them
-to a file when the signal SIGRTMAX - 18 (which is 46 on most Android devices)
+to a file when the signal SIGRTMAX - 18 (which is 46 on Android devices)
 is received.
 
 If TOTAL\_ENTRIES is set, then it indicates the total number of
diff --git a/libc/malloc_debug/Unreachable.cpp b/libc/malloc_debug/Unreachable.cpp
new file mode 100644
index 0000000..af47257
--- /dev/null
+++ b/libc/malloc_debug/Unreachable.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 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 <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <string>
+
+#include <memunreachable/memunreachable.h>
+#include <platform/bionic/macros.h>
+
+#include "Config.h"
+#include "Unreachable.h"
+#include "debug_log.h"
+
+std::atomic_bool Unreachable::do_check_;
+
+static void EnableUnreachableCheck(int, struct siginfo*, void*) {
+  Unreachable::EnableCheck();
+}
+
+void Unreachable::CheckIfRequested(const Config& config) {
+  if ((config.options() & CHECK_UNREACHABLE_ON_SIGNAL) && do_check_.exchange(false)) {
+    info_log("Starting to check for unreachable memory.");
+    if (!LogUnreachableMemory(false, 100)) {
+      error_log("Unreachable check failed, run setenforce 0 and try again.");
+    }
+  }
+}
+
+bool Unreachable::Initialize(const Config& config) {
+  if (!(config.options() & CHECK_UNREACHABLE_ON_SIGNAL)) {
+    return true;
+  }
+
+  struct sigaction64 unreachable_act = {};
+  unreachable_act.sa_sigaction = EnableUnreachableCheck;
+  unreachable_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+  if (sigaction64(config.check_unreachable_signal(), &unreachable_act, nullptr) != 0) {
+    error_log("Unable to set up check unreachable signal function: %s", strerror(errno));
+    return false;
+  }
+
+  if (config.options() & VERBOSE) {
+    info_log("%s: Run: 'kill -%d %d' to check for unreachable memory.", getprogname(),
+             config.check_unreachable_signal(), getpid());
+  }
+
+  return true;
+}
diff --git a/libc/malloc_debug/Unreachable.h b/libc/malloc_debug/Unreachable.h
new file mode 100644
index 0000000..36c0bdb
--- /dev/null
+++ b/libc/malloc_debug/Unreachable.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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>
+
+// Forward declarations
+class ConfigData;
+
+class Unreachable {
+ public:
+  static bool Initialize(const Config& config);
+  static void CheckIfRequested(const Config& config);
+
+  static void EnableCheck() { do_check_ = true; }
+
+ private:
+  static std::atomic_bool do_check_;
+
+  BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(Unreachable);
+};
diff --git a/libc/malloc_debug/UnwindBacktrace.cpp b/libc/malloc_debug/UnwindBacktrace.cpp
index f6c3e69..c892a39 100644
--- a/libc/malloc_debug/UnwindBacktrace.cpp
+++ b/libc/malloc_debug/UnwindBacktrace.cpp
@@ -36,11 +36,7 @@
 #include <vector>
 
 #include <android-base/stringprintf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/AndroidUnwinder.h>
 #include <unwindstack/Unwinder.h>
 
 #include "UnwindBacktrace.h"
@@ -54,51 +50,22 @@
 
 extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
 
-static pthread_once_t g_setup_once = PTHREAD_ONCE_INIT;
-
-static unwindstack::LocalUpdatableMaps* g_maps;
-static std::shared_ptr<unwindstack::Memory> g_process_memory;
-#if defined(__LP64__)
-static std::vector<std::string> g_skip_libraries{"/system/lib64/libunwindstack.so",
-                                                 "/system/lib64/libc_malloc_debug.so"};
-#else
-static std::vector<std::string> g_skip_libraries{"/system/lib/libunwindstack.so",
-                                                 "/system/lib/libc_malloc_debug.so"};
-#endif
-
-static void Setup() {
-  g_maps = new unwindstack::LocalUpdatableMaps;
-  if (!g_maps->Parse()) {
-    delete g_maps;
-    g_maps = nullptr;
-  }
-
-  g_process_memory = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid());
-}
-
 bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::FrameData>* frame_info,
             size_t max_frames) {
-  pthread_once(&g_setup_once, Setup);
-
-  if (g_maps == nullptr) {
-    return false;
-  }
-
-  std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
-  unwindstack::RegsGetLocal(regs.get());
-  unwindstack::Unwinder unwinder(max_frames, g_maps, regs.get(), g_process_memory);
-  unwinder.Unwind(&g_skip_libraries);
-  if (unwinder.NumFrames() == 0) {
+  [[clang::no_destroy]] static unwindstack::AndroidLocalUnwinder unwinder(
+      std::vector<std::string>{"libc_malloc_debug.so"});
+  unwindstack::AndroidUnwinderData data(max_frames);
+  if (!unwinder.Unwind(data)) {
     frames->clear();
     frame_info->clear();
     return false;
   }
-  *frame_info = unwinder.ConsumeFrames();
 
-  frames->resize(frame_info->size());
-  for (size_t i = 0; i < frame_info->size(); i++) {
-    frames->at(i) = frame_info->at(i).pc;
+  frames->resize(data.frames.size());
+  for (const auto& frame : data.frames) {
+    frames->at(frame.num) = frame.pc;
   }
+  *frame_info = std::move(data.frames);
   return true;
 }
 
diff --git a/libc/malloc_debug/UnwindBacktrace.h b/libc/malloc_debug/UnwindBacktrace.h
index 7f89907..091865e 100644
--- a/libc/malloc_debug/UnwindBacktrace.h
+++ b/libc/malloc_debug/UnwindBacktrace.h
@@ -30,10 +30,8 @@
 
 #include <stdint.h>
 
-#include <string>
 #include <vector>
 
-#include <unwindstack/MapInfo.h>
 #include <unwindstack/Unwinder.h>
 
 bool Unwind(std::vector<uintptr_t>* frames, std::vector<unwindstack::FrameData>* info,
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index d608f5d..617858a 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -53,11 +53,12 @@
 
 #include "Config.h"
 #include "DebugData.h"
+#include "Unreachable.h"
+#include "UnwindBacktrace.h"
 #include "backtrace.h"
 #include "debug_disable.h"
 #include "debug_log.h"
 #include "malloc_debug.h"
-#include "UnwindBacktrace.h"
 
 // ------------------------------------------------------------------------
 // Global Data
@@ -315,7 +316,7 @@
   }
 
   DebugData* debug = new DebugData();
-  if (!debug->Initialize(options)) {
+  if (!debug->Initialize(options) || !Unreachable::Initialize(debug->config())) {
     delete debug;
     DebugDisableFinalize();
     return false;
@@ -402,6 +403,8 @@
 }
 
 size_t debug_malloc_usable_size(void* pointer) {
+  Unreachable::CheckIfRequested(g_debug->config());
+
   if (DebugCallsDisabled() || pointer == nullptr) {
     return g_dispatch->malloc_usable_size(pointer);
   }
@@ -467,6 +470,8 @@
 }
 
 void* debug_malloc(size_t size) {
+  Unreachable::CheckIfRequested(g_debug->config());
+
   if (DebugCallsDisabled()) {
     return g_dispatch->malloc(size);
   }
@@ -517,8 +522,8 @@
 
   if (g_debug->config().options() & FILL_ON_FREE) {
     size_t fill_bytes = g_debug->config().fill_on_free_bytes();
-    bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
-    memset(pointer, g_debug->config().fill_free_value(), bytes);
+    fill_bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
+    memset(pointer, g_debug->config().fill_free_value(), fill_bytes);
   }
 
   if (g_debug->TrackPointers()) {
@@ -531,7 +536,7 @@
     // 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.
-    pointer = PointerData::AddFreed(pointer);
+    pointer = PointerData::AddFreed(pointer, bytes);
     if (pointer != nullptr) {
       if (g_debug->HeaderEnabled()) {
         pointer = g_debug->GetHeader(pointer)->orig_pointer;
@@ -544,6 +549,8 @@
 }
 
 void debug_free(void* pointer) {
+  Unreachable::CheckIfRequested(g_debug->config());
+
   if (DebugCallsDisabled() || pointer == nullptr) {
     return g_dispatch->free(pointer);
   }
@@ -563,6 +570,8 @@
 }
 
 void* debug_memalign(size_t alignment, size_t bytes) {
+  Unreachable::CheckIfRequested(g_debug->config());
+
   if (DebugCallsDisabled()) {
     return g_dispatch->memalign(alignment, bytes);
   }
@@ -643,6 +652,8 @@
 }
 
 void* debug_realloc(void* pointer, size_t bytes) {
+  Unreachable::CheckIfRequested(g_debug->config());
+
   if (DebugCallsDisabled()) {
     return g_dispatch->realloc(pointer, bytes);
   }
@@ -763,6 +774,8 @@
 }
 
 void* debug_calloc(size_t nmemb, size_t bytes) {
+  Unreachable::CheckIfRequested(g_debug->config());
+
   if (DebugCallsDisabled()) {
     return g_dispatch->calloc(nmemb, bytes);
   }
@@ -862,6 +875,8 @@
 }
 
 void* debug_aligned_alloc(size_t alignment, size_t size) {
+  Unreachable::CheckIfRequested(g_debug->config());
+
   if (DebugCallsDisabled()) {
     return g_dispatch->aligned_alloc(alignment, size);
   }
@@ -873,6 +888,8 @@
 }
 
 int debug_posix_memalign(void** memptr, size_t alignment, size_t size) {
+  Unreachable::CheckIfRequested(g_debug->config());
+
   if (DebugCallsDisabled()) {
     return g_dispatch->posix_memalign(memptr, alignment, size);
   }
@@ -934,6 +951,8 @@
 
 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
 void* debug_pvalloc(size_t bytes) {
+  Unreachable::CheckIfRequested(g_debug->config());
+
   if (DebugCallsDisabled()) {
     return g_dispatch->pvalloc(bytes);
   }
@@ -949,6 +968,8 @@
 }
 
 void* debug_valloc(size_t size) {
+  Unreachable::CheckIfRequested(g_debug->config());
+
   if (DebugCallsDisabled()) {
     return g_dispatch->valloc(size);
   }
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index 42d1415..0a0eaef 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -761,3 +761,87 @@
       "which does not take a value\n");
   ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
 }
+
+TEST_F(MallocDebugConfigTest, check_unreachable_on_signal) {
+  ASSERT_TRUE(InitConfig("check_unreachable_on_signal")) << getFakeLogPrint();
+  ASSERT_EQ(CHECK_UNREACHABLE_ON_SIGNAL, config->options());
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, trigger_check_unreachable_on_signal_fail) {
+  ASSERT_FALSE(InitConfig("check_unreachable_on_signal=200")) << getFakeLogPrint();
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: value set for option 'check_unreachable_on_signal' "
+      "which does not take a value\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, size) {
+  ASSERT_TRUE(InitConfig("backtrace_size=37")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
+  ASSERT_EQ(37U, config->backtrace_min_size_bytes());
+  ASSERT_EQ(37U, config->backtrace_max_size_bytes());
+
+  ASSERT_FALSE(InitConfig("backtrace_size")) << getFakeLogPrint();
+  ASSERT_FALSE(InitConfig("backtrace_size=0")) << getFakeLogPrint();
+  ASSERT_FALSE(InitConfig("backtrace_size=-1")) << getFakeLogPrint();
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace_size'\n" +
+                      usage_string +
+                      "6 malloc_debug malloc_testing: bad value for option 'backtrace_size', value "
+                      "must be >= 1: 0\n" +
+                      usage_string +
+                      "6 malloc_debug malloc_testing: bad value for option 'backtrace_size', value "
+                      "cannot be negative: -1\n" +
+                      usage_string);
+  ASSERT_STREQ(log_msg.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, min_size) {
+  ASSERT_TRUE(InitConfig("backtrace_min_size=9")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
+  ASSERT_EQ(9U, config->backtrace_min_size_bytes());
+  ASSERT_EQ(SIZE_MAX, config->backtrace_max_size_bytes());
+
+  ASSERT_FALSE(InitConfig("backtrace_min_size")) << getFakeLogPrint();
+  ASSERT_FALSE(InitConfig("backtrace_min_size=0")) << getFakeLogPrint();
+  ASSERT_FALSE(InitConfig("backtrace_min_size=-1")) << getFakeLogPrint();
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace_min_size'\n" +
+                      usage_string +
+                      "6 malloc_debug malloc_testing: bad value for option 'backtrace_min_size', "
+                      "value must be >= 1: 0\n" +
+                      usage_string +
+                      "6 malloc_debug malloc_testing: bad value for option 'backtrace_min_size', "
+                      "value cannot be negative: -1\n" +
+                      usage_string);
+  ASSERT_STREQ(log_msg.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, max_size) {
+  ASSERT_TRUE(InitConfig("backtrace_max_size=13")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
+  ASSERT_EQ(0U, config->backtrace_min_size_bytes());
+  ASSERT_EQ(13U, config->backtrace_max_size_bytes());
+
+  ASSERT_FALSE(InitConfig("backtrace_max_size")) << getFakeLogPrint();
+  ASSERT_FALSE(InitConfig("backtrace_max_size=0")) << getFakeLogPrint();
+  ASSERT_FALSE(InitConfig("backtrace_max_size=-1")) << getFakeLogPrint();
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace_max_size'\n" +
+                      usage_string +
+                      "6 malloc_debug malloc_testing: bad value for option 'backtrace_max_size', "
+                      "value must be >= 1: 0\n" +
+                      usage_string +
+                      "6 malloc_debug malloc_testing: bad value for option 'backtrace_max_size', "
+                      "value cannot be negative: -1\n" +
+                      usage_string);
+  ASSERT_STREQ(log_msg.c_str(), getFakeLogPrint().c_str());
+}
diff --git a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
index 92679e4..aee2572 100644
--- a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
@@ -52,8 +52,7 @@
 #include <thread>
 #include <vector>
 
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
+#include <unwindstack/AndroidUnwinder.h>
 
 #include <bionic/malloc.h>
 #include <tests/utils.h>
@@ -452,12 +451,19 @@
   static constexpr size_t kMaxRetries = 3;
 };
 
-TEST(MallocTests, DISABLED_smoke) {}
+TEST(MallocTests, DISABLED_smoke) {
+  void* ptr = malloc(128);
+  free(ptr);
+}
 
 TEST_F(MallocDebugSystemTest, smoke) {
   Exec("MallocTests.DISABLED_smoke", "verbose backtrace");
 }
 
+TEST_F(MallocDebugSystemTest, backtrace_full_smoke) {
+  Exec("MallocTests.DISABLED_smoke", "verbose backtrace backtrace_full");
+}
+
 static void SetAllocationLimit() {
   // Set to a large value, this is only to enable the limit code and
   // verify that malloc debug is still called properly.
@@ -763,13 +769,14 @@
   }
 
   static constexpr size_t kNumUnwinds = 1000;
+  unwindstack::AndroidLocalUnwinder unwinder;
   for (size_t i = 0; i < kNumUnwinds; i++) {
-    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
     // Only verify that there is at least one frame in the unwind.
     // This is not a test of the unwinder and clang for arm seems to
     // produces an increasing number of code that does not have unwind
     // information.
-    ASSERT_TRUE(backtrace->Unwind(0)) << "Failed on unwind " << i;
+    unwindstack::AndroidUnwinderData data;
+    ASSERT_TRUE(unwinder.Unwind(data)) << "Failed on unwind " << i;
   }
   running = false;
   thread.join();
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index ea2dc78..961ddd3 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -83,6 +83,14 @@
 
 __END_DECLS
 
+// Change the slow threshold since some tests take more than 2 seconds.
+extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
+  static const char* initial_args[] = {"--slow_threshold_ms=5000"};
+  *args = initial_args;
+  *num_args = 1;
+  return true;
+}
+
 constexpr char DIVIDER[] =
     "6 malloc_debug *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n";
 
@@ -90,7 +98,7 @@
   return __BIONIC_ALIGN(sizeof(Header), MINIMUM_ALIGNMENT_BYTES);
 }
 
-static constexpr const char RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs.txt";
+static constexpr const char RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs";
 
 static constexpr const char BACKTRACE_DUMP_PREFIX[] = "/data/local/tmp/backtrace_heap";
 
@@ -100,8 +108,10 @@
     initialized = false;
     resetLogs();
     backtrace_fake_clear_all();
-    // Delete the record data file if it exists.
-    unlink(RECORD_ALLOCS_FILE);
+    if (!record_filename.empty()) {
+      // Delete the record data file if it exists.
+      unlink(record_filename.c_str());
+    }
   }
 
   void TearDown() override {
@@ -116,6 +126,13 @@
     initialized = true;
   }
 
+  void InitRecordAllocs(const char* options) {
+    record_filename = android::base::StringPrintf("%s.%d.txt", RECORD_ALLOCS_FILE, getpid());
+    std::string init(options);
+    init += android::base::StringPrintf(" record_allocs_file=%s", record_filename.c_str());
+    Init(init.c_str());
+  }
+
   void BacktraceDumpOnSignal(bool trigger_with_alloc);
 
   static size_t GetInfoEntrySize(size_t max_frames) {
@@ -126,6 +143,8 @@
 
   bool zygote_child;
 
+  std::string record_filename;
+
   static MallocDispatch dispatch;
 };
 
@@ -227,6 +246,9 @@
     expected_log += android::base::StringPrintf(
         "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to dump the allocation records.\n",
         SIGRTMAX - 18, getpid());
+    expected_log += android::base::StringPrintf(
+        "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to check for unreachable memory.\n",
+        SIGRTMAX - 16, getpid());
   }
   expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
@@ -296,6 +318,16 @@
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
 
+TEST_F(MallocDebugTest, verbose_check_unreachable_on_signal) {
+  Init("verbose check_unreachable_on_signal");
+
+  std::string expected_log = android::base::StringPrintf(
+      "4 malloc_debug malloc_testing: Run: 'kill -%d %d' to check for unreachable memory.\n",
+      SIGRTMAX - 16, getpid());
+  expected_log += "4 malloc_debug malloc_testing: malloc debug enabled\n";
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
 TEST_F(MallocDebugTest, fill_on_free) {
   Init("fill_on_free free_track free_track_backtrace_num_frames=0");
 
@@ -359,7 +391,7 @@
 TEST_F(MallocDebugTest, all_options) {
   Init(
       "guard backtrace backtrace_enable_on_signal fill expand_alloc free_track leak_track "
-      "record_allocs verify_pointers abort_on_error verbose");
+      "record_allocs verify_pointers abort_on_error verbose check_unreachable_on_signal");
   VerifyAllocCalls(true);
 }
 
@@ -2135,7 +2167,7 @@
 }
 #endif
 
-void VerifyRecordAllocs() {
+void VerifyRecordAllocs(const std::string& record_filename) {
   std::string expected;
 
   void* pointer = debug_malloc(10);
@@ -2204,8 +2236,7 @@
 
   // Read all of the contents.
   std::string actual;
-  ASSERT_TRUE(android::base::ReadFileToString(RECORD_ALLOCS_FILE, &actual));
-  ASSERT_EQ(0, unlink(RECORD_ALLOCS_FILE));
+  ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
 
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 
@@ -2216,19 +2247,19 @@
 }
 
 TEST_F(MallocDebugTest, record_allocs_no_header) {
-  Init("record_allocs");
+  InitRecordAllocs("record_allocs");
 
-  VerifyRecordAllocs();
+  VerifyRecordAllocs(record_filename);
 }
 
 TEST_F(MallocDebugTest, record_allocs_with_header) {
-  Init("record_allocs front_guard");
+  InitRecordAllocs("record_allocs front_guard");
 
-  VerifyRecordAllocs();
+  VerifyRecordAllocs(record_filename);
 }
 
 TEST_F(MallocDebugTest, record_allocs_max) {
-  Init("record_allocs=5");
+  InitRecordAllocs("record_allocs=5");
 
   std::string expected;
 
@@ -2259,8 +2290,7 @@
 
   // Read all of the contents.
   std::string actual;
-  ASSERT_TRUE(android::base::ReadFileToString(RECORD_ALLOCS_FILE, &actual));
-  ASSERT_EQ(0, unlink(RECORD_ALLOCS_FILE));
+  ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
 
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 
@@ -2271,7 +2301,7 @@
 }
 
 TEST_F(MallocDebugTest, record_allocs_thread_done) {
-  Init("record_allocs=5");
+  InitRecordAllocs("record_allocs=5");
 
   static pid_t tid = 0;
   static void* pointer = nullptr;
@@ -2298,8 +2328,7 @@
 
   // Read all of the contents.
   std::string actual;
-  ASSERT_TRUE(android::base::ReadFileToString(RECORD_ALLOCS_FILE, &actual));
-  ASSERT_EQ(0, unlink(RECORD_ALLOCS_FILE));
+  ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
 
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 
@@ -2310,13 +2339,13 @@
 }
 
 TEST_F(MallocDebugTest, record_allocs_file_name_fail) {
-  Init("record_allocs=5");
+  InitRecordAllocs("record_allocs=5");
 
   // Delete the special.txt file and create a symbolic link there to
   // make sure the create file will fail.
-  unlink(RECORD_ALLOCS_FILE);
+  unlink(record_filename.c_str());
 
-  ASSERT_EQ(0, symlink("/data/local/tmp/does_not_exist", RECORD_ALLOCS_FILE));
+  ASSERT_EQ(0, symlink("/data/local/tmp/does_not_exist", record_filename.c_str()));
 
   std::string expected;
 
@@ -2337,10 +2366,10 @@
 
   // Read all of the contents.
   std::string actual;
-  ASSERT_FALSE(android::base::ReadFileToString(RECORD_ALLOCS_FILE, &actual));
+  ASSERT_FALSE(android::base::ReadFileToString(record_filename, &actual));
 
   // Unlink the file so the next dump passes.
-  ASSERT_EQ(0, unlink(RECORD_ALLOCS_FILE));
+  ASSERT_EQ(0, unlink(record_filename.c_str()));
 
   // Dump all of the data accumulated so far.
   ASSERT_TRUE(kill(getpid(), SIGRTMAX - 18) == 0);
@@ -2350,14 +2379,13 @@
   debug_free(pointer);
   expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
 
-  ASSERT_TRUE(android::base::ReadFileToString(RECORD_ALLOCS_FILE, &actual));
-  ASSERT_EQ(0, unlink(RECORD_ALLOCS_FILE));
+  ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
   ASSERT_STREQ(expected.c_str(), actual.c_str());
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log = android::base::StringPrintf(
       "6 malloc_debug Cannot create record alloc file %s: Too many symbolic links encountered\n",
-      RECORD_ALLOCS_FILE);
+      record_filename.c_str());
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
 
@@ -2695,3 +2723,209 @@
   std::string expected_log = std::string("6 malloc_debug Dumping to file: ") + tf.path + "\n\n";
   ASSERT_EQ(expected_log, getFakeLogPrint());
 }
+
+extern "C" bool LogUnreachableMemory(bool, size_t) {
+  static bool return_value = false;
+  return_value = !return_value;
+  return return_value;
+}
+
+TEST_F(MallocDebugTest, check_unreachable_on_signal) {
+  Init("check_unreachable_on_signal");
+
+  ASSERT_TRUE(kill(getpid(), SIGRTMAX - 16) == 0);
+  sleep(1);
+
+  // The first unreachable check will pass.
+  void* pointer = debug_malloc(110);
+  ASSERT_TRUE(pointer != nullptr);
+
+  ASSERT_TRUE(kill(getpid(), SIGRTMAX - 16) == 0);
+  sleep(1);
+
+  // The second unreachable check will fail.
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string expected_log = "4 malloc_debug Starting to check for unreachable memory.\n";
+  ASSERT_STREQ(
+      "4 malloc_debug Starting to check for unreachable memory.\n"
+      "4 malloc_debug Starting to check for unreachable memory.\n"
+      "6 malloc_debug Unreachable check failed, run setenforce 0 and try again.\n",
+      getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, backtrace_only_some_sizes_with_backtrace_size) {
+  Init("leak_track backtrace backtrace_size=120");
+
+  backtrace_fake_add(std::vector<uintptr_t>{0x1000, 0x2000, 0x3000});
+
+  void* pointer1 = debug_malloc(119);
+  ASSERT_TRUE(pointer1 != nullptr);
+
+  backtrace_fake_add(std::vector<uintptr_t>{0xa000, 0xb000, 0xc000, 0xd000});
+
+  void* pointer2 = debug_malloc(120);
+  ASSERT_TRUE(pointer2 != nullptr);
+
+  backtrace_fake_add(std::vector<uintptr_t>{0xfe000, 0xde000, 0xce000, 0xbe000, 0xae000});
+
+  void* pointer3 = debug_malloc(121);
+  ASSERT_TRUE(pointer3 != nullptr);
+
+  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 121 at %p (leak 1 of 3)\n", pointer3);
+
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 120 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 0x1000\n";
+  expected_log += "6 malloc_debug   #01 pc 0x2000\n";
+  expected_log += "6 malloc_debug   #02 pc 0x3000\n";
+
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 119 at %p (leak 3 of 3)\n", pointer1);
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, backtrace_only_some_sizes_with_backtrace_min_size) {
+  Init("leak_track backtrace backtrace_min_size=1000");
+
+  backtrace_fake_add(std::vector<uintptr_t>{0x1000, 0x2000, 0x3000});
+
+  void* pointer1 = debug_malloc(500);
+  ASSERT_TRUE(pointer1 != nullptr);
+
+  backtrace_fake_add(std::vector<uintptr_t>{0xa000, 0xb000, 0xc000, 0xd000});
+
+  void* pointer2 = debug_malloc(1000);
+  ASSERT_TRUE(pointer2 != nullptr);
+
+  backtrace_fake_add(std::vector<uintptr_t>{0xfe000, 0xde000, 0xce000, 0xbe000, 0xae000});
+
+  void* pointer3 = debug_malloc(1001);
+  ASSERT_TRUE(pointer3 != nullptr);
+
+  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 1001 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 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 1000 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 0x1000\n";
+  expected_log += "6 malloc_debug   #01 pc 0x2000\n";
+  expected_log += "6 malloc_debug   #02 pc 0x3000\n";
+
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 500 at %p (leak 3 of 3)\n", pointer1);
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugTest, backtrace_only_some_sizes_with_backtrace_max_size) {
+  Init("leak_track backtrace backtrace_max_size=1000");
+
+  backtrace_fake_add(std::vector<uintptr_t>{0x1000, 0x2000, 0x3000});
+
+  void* pointer1 = debug_malloc(1000);
+  ASSERT_TRUE(pointer1 != nullptr);
+
+  backtrace_fake_add(std::vector<uintptr_t>{0xa000, 0xb000, 0xc000, 0xd000});
+
+  void* pointer2 = debug_malloc(1001);
+  ASSERT_TRUE(pointer2 != nullptr);
+
+  backtrace_fake_add(std::vector<uintptr_t>{0xfe000, 0xde000, 0xce000, 0xbe000, 0xae000});
+
+  void* pointer3 = debug_malloc(5000);
+  ASSERT_TRUE(pointer3 != nullptr);
+
+  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 5000 at %p (leak 1 of 3)\n",
+      pointer3);
+
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 1001 at %p (leak 2 of 3)\n",
+      pointer2);
+
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 1000 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, backtrace_only_some_sizes_with_backtrace_min_max_size) {
+  Init("leak_track backtrace backtrace_min_size=50 backtrace_max_size=1000");
+
+  backtrace_fake_add(std::vector<uintptr_t>{0x1000, 0x2000, 0x3000});
+
+  void* pointer1 = debug_malloc(49);
+  ASSERT_TRUE(pointer1 != nullptr);
+
+  backtrace_fake_add(std::vector<uintptr_t>{0xa000, 0xb000, 0xc000, 0xd000});
+
+  void* pointer2 = debug_malloc(50);
+  ASSERT_TRUE(pointer2 != nullptr);
+
+  backtrace_fake_add(std::vector<uintptr_t>{0xfe000, 0xde000, 0xce000, 0xbe000, 0xae000});
+
+  void* pointer3 = debug_malloc(1000);
+  ASSERT_TRUE(pointer3 != nullptr);
+
+  backtrace_fake_add(std::vector<uintptr_t>{0x1a000, 0x1b000, 0x1c000, 0x1d000, 0x1e000});
+
+  void* pointer4 = debug_malloc(1001);
+  ASSERT_TRUE(pointer4 != nullptr);
+
+  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 1001 at %p (leak 1 of 4)\n",
+      pointer4);
+
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 1000 at %p (leak 2 of 4)\n",
+      pointer3);
+  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 50 at %p (leak 3 of 4)\n", pointer2);
+  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";
+
+  expected_log += android::base::StringPrintf(
+      "6 malloc_debug +++ malloc_testing leaked block of size 49 at %p (leak 4 of 4)\n", pointer1);
+
+  ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
+}
diff --git a/tests/Android.bp b/tests/Android.bp
index a54ffb8..6a41cf2 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -331,8 +331,8 @@
 cc_test_library {
     name: "clang_diagnostic_tests",
     cflags: [
-      "-Xclang",
-      "-verify",
+        "-Xclang",
+        "-verify",
     ],
     srcs: ["sys_ioctl_diag_test.cpp"],
 }
@@ -641,9 +641,6 @@
     ],
     tidy: false,
     target: {
-        host: {
-            clang_cflags: ["-D__clang__"],
-        },
         musl: {
             // Musl doesn't have fortify
             enabled: false,
@@ -727,7 +724,7 @@
     tidy: false,
     target: {
         host: {
-            clang_cflags: ["-D__clang__"],
+            cflags: ["-D__clang__"],
         },
     },
 }
@@ -762,7 +759,6 @@
     },
 }
 
-
 // -----------------------------------------------------------------------------
 // Library of all tests (excluding the dynamic linker tests).
 // -----------------------------------------------------------------------------
diff --git a/tests/mntent_test.cpp b/tests/mntent_test.cpp
index b86af9f..4b8fc9a 100644
--- a/tests/mntent_test.cpp
+++ b/tests/mntent_test.cpp
@@ -19,24 +19,40 @@
 #include <mntent.h>
 
 TEST(mntent, mntent_smoke) {
+  // Read all the entries with getmntent().
   FILE* fp = setmntent("/proc/mounts", "r");
   ASSERT_TRUE(fp != nullptr);
 
-  ASSERT_TRUE(getmntent(fp) != nullptr);
+  std::vector<std::string> fsnames;
+  std::vector<std::string> dirs;
+  mntent* me;
+  while ((me = getmntent(fp)) != nullptr) {
+    fsnames.push_back(me->mnt_fsname);
+    dirs.push_back(me->mnt_dir);
+  }
 
-  bool saw_proc = false;
+  ASSERT_EQ(1, endmntent(fp));
+
+  // Then again with getmntent_r(), checking they match.
+  fp = setmntent("/proc/mounts", "r");
+  ASSERT_TRUE(fp != nullptr);
 
   struct mntent entry;
   char buf[BUFSIZ];
+  size_t i = 0;
   while (getmntent_r(fp, &entry, buf, sizeof(buf)) != nullptr) {
-    if (strcmp(entry.mnt_fsname, "proc") == 0 && strcmp(entry.mnt_dir, "/proc") == 0) {
-      saw_proc = true;
-    }
+    ASSERT_EQ(fsnames[i], entry.mnt_fsname);
+    ASSERT_EQ(dirs[i], entry.mnt_dir);
+    i++;
   }
 
-  ASSERT_TRUE(saw_proc);
-
   ASSERT_EQ(1, endmntent(fp));
+
+  // And just for good measure: we did see a /proc entry, right?
+  auto it = std::find(fsnames.begin(), fsnames.end(), "proc");
+  ASSERT_TRUE(it != fsnames.end());
+  size_t proc_index = it - fsnames.begin();
+  ASSERT_EQ("/proc", dirs[proc_index]);
 }
 
 TEST(mntent, hasmntopt) {
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 293b45a..49fec12 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -1668,3 +1668,19 @@
   }
 #endif  // __GLIBC__
 }
+
+TEST(UNISTD_TEST, copy_file_range) {
+#if defined(__GLIBC__)
+  GTEST_SKIP() << "glibc too old";
+#else   // __GLIBC__
+  TemporaryFile tf;
+  ASSERT_TRUE(android::base::WriteStringToFd("hello world", tf.fd));
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+  TemporaryFile tf2;
+  ASSERT_EQ(11, copy_file_range(tf.fd, NULL, tf2.fd, NULL, 11, 0));
+  ASSERT_EQ(0, lseek(tf2.fd, SEEK_SET, 0));
+  std::string content;
+  ASSERT_TRUE(android::base::ReadFdToString(tf2.fd, &content));
+  ASSERT_EQ("hello world", content);
+#endif  // __GLIBC__
+}
\ No newline at end of file