Merge "Update kernel update documentation."
diff --git a/libc/Android.bp b/libc/Android.bp
index f5f9507..4084b96 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -21,7 +21,6 @@
 }
 
 libc_common_src_files = [
-    "async_safe/async_safe_log.cpp",
     "bionic/ether_aton.c",
     "bionic/ether_ntoa.c",
     "bionic/exit.cpp",
@@ -1291,7 +1290,6 @@
     cmd: "$(location :bionic-gensyscalls) arm $(in) > $(out)",
     bazel_module: {
         bp2build_available: true,
-        label: "//bionic/libc:syscalls-arm.S"
     }
 }
 
@@ -1303,7 +1301,6 @@
     cmd: "$(location :bionic-gensyscalls) arm64 $(in) > $(out)",
     bazel_module: {
         bp2build_available: true,
-        label: "//bionic/libc:syscalls-arm64.S"
     },
 }
 
@@ -1315,7 +1312,6 @@
     cmd: "$(location :bionic-gensyscalls) x86 $(in) > $(out)",
     bazel_module: {
         bp2build_available: true,
-        label: "//bionic/libc:syscalls-x86.S"
     },
 }
 
@@ -1327,7 +1323,6 @@
     cmd: "$(location :bionic-gensyscalls) x86_64 $(in) > $(out)",
     bazel_module: {
         bp2build_available: true,
-        label: "//bionic/libc:syscalls-x86_64.S"
     },
 }
 
@@ -1420,6 +1415,7 @@
     whole_static_libs: [
         "gwp_asan",
         "libarm-optimized-routines-string",
+        "libasync_safe",
         "libc_bionic_ndk",
         "libc_bootstrap",
         "libc_fortify",
@@ -1451,6 +1447,7 @@
 
     whole_static_libs: [
         "libarm-optimized-routines-string",
+        "libasync_safe",
         "libc_bionic",
         "libc_bionic_ndk",
         "libc_bootstrap",
@@ -2126,7 +2123,10 @@
 
 cc_object {
     name: "crtend_so",
-    local_include_dirs: ["include"],
+    local_include_dirs: [
+        "include",
+        "private",  // crtend_so.S depends on private/bionic_asm_arm64.h
+    ],
     srcs: ["arch-common/bionic/crtend_so.S"],
 
     defaults: ["crt_so_defaults"],
@@ -2181,7 +2181,10 @@
     // We rename crtend.o to crtend_android.o to avoid a
     // name clash between gcc and bionic.
     name: "crtend_android",
-    local_include_dirs: ["include"],
+    local_include_dirs: [
+        "include",
+        "private",  // crtend.S depends on private/bionic_asm_arm64.h
+    ],
     srcs: ["arch-common/bionic/crtend.S"],
 
     defaults: ["crt_defaults"],
@@ -2196,6 +2199,7 @@
         srcs: ["arch-arm64/bionic/note_memtag_heap_async.S"],
       }
     },
+    sdk_version: "minimum",
 
     defaults: ["crt_defaults"],
 }
@@ -2207,6 +2211,7 @@
         srcs: ["arch-arm64/bionic/note_memtag_heap_sync.S"],
       }
     },
+    sdk_version: "minimum",
 
     defaults: ["crt_defaults"],
 }
diff --git a/libc/arch-common/bionic/crtbegin.c b/libc/arch-common/bionic/crtbegin.c
index f2b6638..62878378 100644
--- a/libc/arch-common/bionic/crtbegin.c
+++ b/libc/arch-common/bionic/crtbegin.c
@@ -89,6 +89,3 @@
 #include "__dso_handle.h"
 #include "atexit.h"
 #include "pthread_atfork.h"
-#ifdef __i386__
-# include "../../arch-x86/bionic/__stack_chk_fail_local.h"
-#endif
diff --git a/libc/arch-common/bionic/crtbegin_so.c b/libc/arch-common/bionic/crtbegin_so.c
index cf369cc..2f3b118 100644
--- a/libc/arch-common/bionic/crtbegin_so.c
+++ b/libc/arch-common/bionic/crtbegin_so.c
@@ -73,6 +73,3 @@
 # include "atexit.h"
 #endif
 #include "pthread_atfork.h"
-#ifdef __i386__
-# include "../../arch-x86/bionic/__stack_chk_fail_local.h"
-#endif
diff --git a/libc/arch-x86/bionic/__stack_chk_fail_local.h b/libc/arch-x86/bionic/__stack_chk_fail_local.h
deleted file mode 100644
index 0b0fd7f..0000000
--- a/libc/arch-x86/bionic/__stack_chk_fail_local.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2012 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 <sys/cdefs.h>
-
-/*
-   __stack_chk_fail routine is runtime part of stack protector compiler
-   feature. It's implemented in libc and represents die routine when stack
-   corruption is detected.
-
-   Calls are generated by compiler and injected into user functions when
-   -fstack-protector* options are used.
-
-   __stack_chk_fail_local is wrapper for __stack_chk_fail. Compiler generates
-   wrapper calls instead for PIC code only and only on IA32 for optimization
-   purpose (see gcc/config/i386/i386.c). Wrapper body is always included into
-   executable or library. This is the idea of optimization.
-
-   Glibc is doing this via libc_nonshared.a which is linked automatically
-   everytime with libc.so. In bionic we have to bring it within crtfiles
-   because libc.so is real library and not a link script like libc.so at glibc.
-
-   For x86_64 or non-PIC code compiler always generates __stack_chk_fail calls.
-*/
-
-#ifdef __i386__
-extern void __stack_chk_fail();
-
-__LIBC_HIDDEN__ void __stack_chk_fail_local() {
-  __stack_chk_fail();
-}
-#endif
diff --git a/libc/bionic/scandir.cpp b/libc/bionic/scandir.cpp
index 6a7e368..f528286 100644
--- a/libc/bionic/scandir.cpp
+++ b/libc/bionic/scandir.cpp
@@ -16,8 +16,9 @@
 
 #include <dirent.h>
 
-#include <fcntl.h>
+#include <assert.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -32,10 +33,8 @@
   }
 
   ~ScandirResult() {
-    while (size_ > 0) {
-      free(names_[--size_]);
-    }
-    free(names_);
+    // We always call release(), so this can't happen.
+    if (names_ != nullptr) __assert(__FILE__, __LINE__, "missing call to release()");
   }
 
   size_t size() {
diff --git a/libfdtrack/fdtrack.cpp b/libfdtrack/fdtrack.cpp
index 898bc43..fd56274 100644
--- a/libfdtrack/fdtrack.cpp
+++ b/libfdtrack/fdtrack.cpp
@@ -31,9 +31,12 @@
 
 #include <array>
 #include <mutex>
+#include <thread>
+#include <utility>
 #include <vector>
 
 #include <android/fdsan.h>
+#include <android/set_abort_message.h>
 #include <bionic/fdtrack.h>
 
 #include <android-base/no_destructor.h>
@@ -48,6 +51,7 @@
 };
 
 extern "C" void fdtrack_dump();
+extern "C" void fdtrack_dump_fatal();
 
 using fdtrack_callback_t = bool (*)(int fd, const char* const* function_names,
                                     const uint64_t* function_offsets, size_t count, void* arg);
@@ -74,7 +78,17 @@
     entry.backtrace.reserve(kStackDepth);
   }
 
-  signal(BIONIC_SIGNAL_FDTRACK, [](int) { fdtrack_dump(); });
+  struct sigaction sa = {};
+  sa.sa_sigaction = [](int, siginfo_t* siginfo, void*) {
+    if (siginfo->si_code == SI_QUEUE && siginfo->si_int == 1) {
+      fdtrack_dump_fatal();
+    } else {
+      fdtrack_dump();
+    }
+  };
+  sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
+  sigaction(BIONIC_SIGNAL_FDTRACK, &sa, nullptr);
+
   if (Unwinder().Init()) {
     android_fdtrack_hook_t expected = nullptr;
     installed = android_fdtrack_compare_exchange_hook(&expected, &fd_hook);
@@ -156,16 +170,47 @@
   android_fdtrack_set_enabled(prev);
 }
 
-void fdtrack_dump() {
+static size_t hash_stack(const char* const* function_names, const uint64_t* function_offsets,
+                         size_t stack_depth) {
+  size_t hash = 0;
+  for (size_t i = 0; i < stack_depth; ++i) {
+    // To future maintainers: if a libc++ update ever makes this invalid, replace this with +.
+    hash = std::__hash_combine(hash, std::hash<std::string_view>()(function_names[i]));
+    hash = std::__hash_combine(hash, std::hash<uint64_t>()(function_offsets[i]));
+  }
+  return hash;
+}
+
+static void fdtrack_dump_impl(bool fatal) {
   if (!installed) {
     async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack not installed");
   } else {
     async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack dumping...");
   }
 
+  // If we're aborting, identify the most common stack in the hopes that it's the culprit,
+  // and emit that in the abort message so crash reporting can separate different fd leaks out.
+  // This is horrible and quadratic, but we need to avoid allocation since this can happen in
+  // response to a signal generated asynchronously. We're only going to dump 1k fds by default,
+  // and we're about to blow up the entire system, so this isn't too expensive.
+  struct StackInfo {
+    size_t hash = 0;
+    size_t count = 0;
+
+    size_t stack_depth = 0;
+    const char* function_names[kStackDepth - kStackFrameSkip];
+    uint64_t function_offsets[kStackDepth - kStackFrameSkip];
+  };
+  struct StackList {
+    size_t count = 0;
+    std::array<StackInfo, 128> data;
+  };
+  static StackList stacks;
+
   fdtrack_iterate(
-      [](int fd, const char* const* function_names, const uint64_t* function_offsets, size_t count,
-         void*) {
+      [](int fd, const char* const* function_names, const uint64_t* function_offsets,
+         size_t stack_depth, void* stacks_ptr) {
+        auto stacks = static_cast<StackList*>(stacks_ptr);
         uint64_t fdsan_owner = android_fdsan_get_owner_tag(fd);
         if (fdsan_owner != 0) {
           async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (owner = 0x%" PRIx64 ")", fd,
@@ -174,12 +219,81 @@
           async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (unowned)", fd);
         }
 
-        for (size_t i = 0; i < count; ++i) {
+        for (size_t i = 0; i < stack_depth; ++i) {
           async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "  %zu: %s+%" PRIu64, i,
                                 function_names[i], function_offsets[i]);
         }
 
+        if (stacks) {
+          size_t hash = hash_stack(function_names, function_offsets, stack_depth);
+          bool found_stack = false;
+          for (size_t i = 0; i < stacks->count; ++i) {
+            if (stacks->data[i].hash == hash) {
+              ++stacks->data[i].count;
+              found_stack = true;
+              break;
+            }
+          }
+
+          if (!found_stack) {
+            if (stacks->count < stacks->data.size()) {
+              auto& stack = stacks->data[stacks->count++];
+              stack.hash = hash;
+              stack.count = 1;
+              stack.stack_depth = stack_depth;
+              for (size_t i = 0; i < stack_depth; ++i) {
+                stack.function_names[i] = function_names[i];
+                stack.function_offsets[i] = function_offsets[i];
+              }
+            }
+          }
+        }
+
         return true;
       },
-      nullptr);
+      fatal ? &stacks : nullptr);
+
+  if (fatal) {
+    // Find the most common stack.
+    size_t max = 0;
+    StackInfo* stack = nullptr;
+    for (size_t i = 0; i < stacks.count; ++i) {
+      if (stacks.data[i].count > max) {
+        stack = &stacks.data[i];
+        max = stack->count;
+      }
+    }
+
+    static char buf[1024];
+
+    if (!stack) {
+      async_safe_format_buffer(buf, sizeof(buf),
+                               "aborting due to fd leak: failed to find most common stack");
+    } else {
+      char* p = buf;
+      p += async_safe_format_buffer(buf, sizeof(buf),
+                                    "aborting due to fd leak: most common stack =\n");
+
+      for (size_t i = 0; i < stack->stack_depth; ++i) {
+        ssize_t bytes_left = buf + sizeof(buf) - p;
+        if (bytes_left > 0) {
+          p += async_safe_format_buffer(p, buf + sizeof(buf) - p, "  %zu: %s+%" PRIu64 "\n", i,
+                                        stack->function_names[i], stack->function_offsets[i]);
+        }
+      }
+    }
+
+    android_set_abort_message(buf);
+
+    // Abort on a different thread to avoid ART dumping runtime stacks.
+    std::thread([]() { abort(); }).join();
+  }
+}
+
+void fdtrack_dump() {
+  fdtrack_dump_impl(false);
+}
+
+void fdtrack_dump_fatal() {
+  fdtrack_dump_impl(true);
 }
diff --git a/libfdtrack/libfdtrack.map.txt b/libfdtrack/libfdtrack.map.txt
index 7a23954..6c4015c 100644
--- a/libfdtrack/libfdtrack.map.txt
+++ b/libfdtrack/libfdtrack.map.txt
@@ -1,6 +1,7 @@
 LIBFDTRACK {
   global:
     fdtrack_dump;
+    fdtrack_dump_fatal;
     fdtrack_iterate;
   local:
     *;