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:
*;