Merge "<sys/thread_properties.h>: remove stray semicolon in the implementation." into main
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 091f711..c2abdea 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -240,7 +240,7 @@
// On LP64, we could use more but there's no obvious advantage to doing
// so, and the various media processes use RLIMIT_AS as a way to limit
// the amount of allocation they'll do.
-#define PTHREAD_GUARD_SIZE max_page_size()
+#define PTHREAD_GUARD_SIZE max_android_page_size()
// SIGSTKSZ (8KiB) is not big enough.
// An snprintf to a stack buffer of size PATH_MAX consumes ~7KiB of stack.
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 2732214..bc708e1 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -113,8 +113,22 @@
*/
pid_t vfork(void) __returns_twice;
+/**
+ * [getpid(2)](http://man7.org/linux/man-pages/man2/getpid.2.html) returns
+ * the caller's process ID.
+ *
+ * Returns the caller's process ID.
+ */
pid_t getpid(void);
-pid_t gettid(void) __attribute_const__;
+
+/**
+ * [gettid(2)](http://man7.org/linux/man-pages/man2/gettid.2.html) returns
+ * the caller's thread ID.
+ *
+ * Returns the caller's thread ID.
+ */
+pid_t gettid(void);
+
pid_t getpgid(pid_t __pid);
int setpgid(pid_t __pid, pid_t __pgid);
pid_t getppid(void);
diff --git a/libc/malloc_debug/MapData.cpp b/libc/malloc_debug/MapData.cpp
index b22c109..c58882a 100644
--- a/libc/malloc_debug/MapData.cpp
+++ b/libc/malloc_debug/MapData.cpp
@@ -34,6 +34,8 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/uio.h>
+#include <unistd.h>
#include <vector>
@@ -69,148 +71,132 @@
MapEntry* entry = new MapEntry(start, end, offset, name, name_len, flags);
if (!(flags & PROT_READ)) {
- // Any unreadable map will just get a zero load bias.
- entry->load_bias = 0;
- entry->init = true;
- entry->valid = false;
+ // This will make sure that an unreadable map will prevent attempts to read
+ // elf data from the map.
+ entry->SetInvalid();
}
return entry;
}
-template <typename T>
-static inline bool get_val(MapEntry* entry, uintptr_t addr, T* store) {
- if (!(entry->flags & PROT_READ) || addr < entry->start || addr + sizeof(T) > entry->end) {
- return false;
+void MapEntry::Init() {
+ if (init_) {
+ return;
}
- // Make sure the address is aligned properly.
- if (addr & (sizeof(T) - 1)) {
- return false;
- }
- *store = *reinterpret_cast<T*>(addr);
- return true;
-}
+ init_ = true;
-static bool valid_elf(MapEntry* entry) {
- uintptr_t addr = entry->start;
- uintptr_t end;
- if (__builtin_add_overflow(addr, SELFMAG, &end) || end >= entry->end) {
- return false;
+ uintptr_t end_addr;
+ if (__builtin_add_overflow(start_, SELFMAG, &end_addr) || end_addr >= end_) {
+ return;
}
- return memcmp(reinterpret_cast<void*>(addr), ELFMAG, SELFMAG) == 0;
-}
-
-static void read_loadbias(MapEntry* entry) {
- entry->load_bias = 0;
- uintptr_t addr = entry->start;
ElfW(Ehdr) ehdr;
- if (!get_val<ElfW(Half)>(entry, addr + offsetof(ElfW(Ehdr), e_phnum), &ehdr.e_phnum)) {
- return;
+ struct iovec src_io = {.iov_base = reinterpret_cast<void*>(start_), .iov_len = SELFMAG};
+ struct iovec dst_io = {.iov_base = ehdr.e_ident, .iov_len = SELFMAG};
+ ssize_t rc = process_vm_readv(getpid(), &dst_io, 1, &src_io, 1, 0);
+ valid_ = rc == SELFMAG && IS_ELF(ehdr);
+}
+
+uintptr_t MapEntry::GetLoadBias() {
+ if (!valid_) {
+ return 0;
}
- if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Ehdr), e_phoff), &ehdr.e_phoff)) {
- return;
+
+ if (load_bias_read_) {
+ return load_bias_;
}
- addr += ehdr.e_phoff;
+
+ load_bias_read_ = true;
+
+ ElfW(Ehdr) ehdr;
+ struct iovec src_io = {.iov_base = reinterpret_cast<void*>(start_), .iov_len = sizeof(ehdr)};
+ struct iovec dst_io = {.iov_base = &ehdr, .iov_len = sizeof(ehdr)};
+ ssize_t rc = process_vm_readv(getpid(), &dst_io, 1, &src_io, 1, 0);
+ if (rc != sizeof(ehdr)) {
+ return 0;
+ }
+
+ uintptr_t addr = start_ + ehdr.e_phoff;
for (size_t i = 0; i < ehdr.e_phnum; i++) {
ElfW(Phdr) phdr;
- if (!get_val<ElfW(Word)>(entry, addr + offsetof(ElfW(Phdr), p_type), &phdr.p_type)) {
- return;
- }
- if (!get_val<ElfW(Word)>(entry, addr + offsetof(ElfW(Phdr), p_flags), &phdr.p_flags)) {
- return;
- }
- if (!get_val<ElfW(Off)>(entry, addr + offsetof(ElfW(Phdr), p_offset), &phdr.p_offset)) {
- return;
+
+ src_io.iov_base = reinterpret_cast<void*>(addr);
+ src_io.iov_len = sizeof(phdr);
+ dst_io.iov_base = &phdr;
+ dst_io.iov_len = sizeof(phdr);
+ rc = process_vm_readv(getpid(), &dst_io, 1, &src_io, 1, 0);
+ if (rc != sizeof(phdr)) {
+ return 0;
}
if ((phdr.p_type == PT_LOAD) && (phdr.p_flags & PF_X) ) {
- if (!get_val<ElfW(Addr)>(entry, addr + offsetof(ElfW(Phdr), p_vaddr), &phdr.p_vaddr)) {
- return;
- }
- entry->load_bias = phdr.p_vaddr - phdr.p_offset;
- return;
+ load_bias_ = phdr.p_vaddr - phdr.p_offset;
+ return load_bias_;
}
addr += sizeof(phdr);
}
+ return 0;
}
-static void inline init(MapEntry* entry) {
- if (entry->init) {
- return;
- }
- entry->init = true;
- if (valid_elf(entry)) {
- entry->valid = true;
- read_loadbias(entry);
- }
-}
-
-bool MapData::ReadMaps() {
+void MapData::ReadMaps() {
+ std::lock_guard<std::mutex> lock(m_);
FILE* fp = fopen("/proc/self/maps", "re");
if (fp == nullptr) {
- return false;
+ return;
}
+ ClearEntries();
+
std::vector<char> buffer(1024);
while (fgets(buffer.data(), buffer.size(), fp) != nullptr) {
MapEntry* entry = parse_line(buffer.data());
if (entry == nullptr) {
- fclose(fp);
- return false;
+ break;
}
-
- auto it = entries_.find(entry);
- if (it == entries_.end()) {
- entries_.insert(entry);
- } else {
- delete entry;
- }
+ entries_.insert(entry);
}
fclose(fp);
- return true;
}
-MapData::~MapData() {
+void MapData::ClearEntries() {
for (auto* entry : entries_) {
delete entry;
}
entries_.clear();
}
+MapData::~MapData() {
+ ClearEntries();
+}
+
// Find the containing map info for the PC.
const MapEntry* MapData::find(uintptr_t pc, uintptr_t* rel_pc) {
MapEntry pc_entry(pc);
std::lock_guard<std::mutex> lock(m_);
-
auto it = entries_.find(&pc_entry);
if (it == entries_.end()) {
- ReadMaps();
- }
- it = entries_.find(&pc_entry);
- if (it == entries_.end()) {
return nullptr;
}
MapEntry* entry = *it;
- init(entry);
+ entry->Init();
if (rel_pc != nullptr) {
// Need to check to see if this is a read-execute map and the read-only
// map is the previous one.
- if (!entry->valid && it != entries_.begin()) {
+ if (!entry->valid() && it != entries_.begin()) {
MapEntry* prev_entry = *--it;
- if (prev_entry->flags == PROT_READ && prev_entry->offset < entry->offset &&
- prev_entry->name == entry->name) {
- init(prev_entry);
+ if (prev_entry->flags() == PROT_READ && prev_entry->offset() < entry->offset() &&
+ prev_entry->name() == entry->name()) {
+ prev_entry->Init();
- if (prev_entry->valid) {
- entry->elf_start_offset = prev_entry->offset;
- *rel_pc = pc - entry->start + entry->offset + prev_entry->load_bias;
+ if (prev_entry->valid()) {
+ entry->set_elf_start_offset(prev_entry->offset());
+ *rel_pc = pc - entry->start() + entry->offset() + prev_entry->GetLoadBias();
return entry;
}
}
}
- *rel_pc = pc - entry->start + entry->offset + entry->load_bias;
+ *rel_pc = pc - entry->start() + entry->offset() + entry->GetLoadBias();
}
return entry;
}
diff --git a/libc/malloc_debug/MapData.h b/libc/malloc_debug/MapData.h
index f2b3c1c..13bf9cb 100644
--- a/libc/malloc_debug/MapData.h
+++ b/libc/malloc_debug/MapData.h
@@ -36,26 +36,50 @@
#include <platform/bionic/macros.h>
-struct MapEntry {
- MapEntry(uintptr_t start, uintptr_t end, uintptr_t offset, const char* name, size_t name_len, int flags)
- : start(start), end(end), offset(offset), name(name, name_len), flags(flags) {}
+class MapEntry {
+ public:
+ MapEntry() = default;
+ MapEntry(uintptr_t start, uintptr_t end, uintptr_t offset, const char* name, size_t name_len,
+ int flags)
+ : start_(start), end_(end), offset_(offset), name_(name, name_len), flags_(flags) {}
- explicit MapEntry(uintptr_t pc) : start(pc), end(pc) {}
+ explicit MapEntry(uintptr_t pc) : start_(pc), end_(pc) {}
- uintptr_t start;
- uintptr_t end;
- uintptr_t offset;
- uintptr_t load_bias;
- uintptr_t elf_start_offset = 0;
- std::string name;
- int flags;
- bool init = false;
- bool valid = false;
+ void Init();
+
+ uintptr_t GetLoadBias();
+
+ void SetInvalid() {
+ valid_ = false;
+ init_ = true;
+ load_bias_read_ = true;
+ }
+
+ bool valid() { return valid_; }
+ uintptr_t start() const { return start_; }
+ uintptr_t end() const { return end_; }
+ uintptr_t offset() const { return offset_; }
+ uintptr_t elf_start_offset() const { return elf_start_offset_; }
+ void set_elf_start_offset(uintptr_t elf_start_offset) { elf_start_offset_ = elf_start_offset; }
+ const std::string& name() const { return name_; }
+ int flags() const { return flags_; }
+
+ private:
+ uintptr_t start_;
+ uintptr_t end_;
+ uintptr_t offset_;
+ uintptr_t load_bias_ = 0;
+ uintptr_t elf_start_offset_ = 0;
+ std::string name_;
+ int flags_;
+ bool init_ = false;
+ bool valid_ = false;
+ bool load_bias_read_ = false;
};
// Ordering comparator that returns equivalence for overlapping entries
struct compare_entries {
- bool operator()(const MapEntry* a, const MapEntry* b) const { return a->end <= b->start; }
+ bool operator()(const MapEntry* a, const MapEntry* b) const { return a->end() <= b->start(); }
};
class MapData {
@@ -65,11 +89,15 @@
const MapEntry* find(uintptr_t pc, uintptr_t* rel_pc = nullptr);
- private:
- bool ReadMaps();
+ size_t NumMaps() { return entries_.size(); }
+ void ReadMaps();
+
+ private:
std::mutex m_;
std::set<MapEntry*, compare_entries> entries_;
+ void ClearEntries();
+
BIONIC_DISALLOW_COPY_AND_ASSIGN(MapData);
};
diff --git a/libc/malloc_debug/backtrace.cpp b/libc/malloc_debug/backtrace.cpp
index ecb3a80..6a32fca 100644
--- a/libc/malloc_debug/backtrace.cpp
+++ b/libc/malloc_debug/backtrace.cpp
@@ -50,7 +50,7 @@
typedef struct _Unwind_Context __unwind_context;
static MapData g_map_data;
-static const MapEntry* g_current_code_map = nullptr;
+static MapEntry g_current_code_map;
static _Unwind_Reason_Code find_current_map(__unwind_context* context, void*) {
uintptr_t ip = _Unwind_GetIP(context);
@@ -58,11 +58,15 @@
if (ip == 0) {
return _URC_END_OF_STACK;
}
- g_current_code_map = g_map_data.find(ip);
+ auto map = g_map_data.find(ip);
+ if (map != nullptr) {
+ g_current_code_map = *map;
+ }
return _URC_END_OF_STACK;
}
void backtrace_startup() {
+ g_map_data.ReadMaps();
_Unwind_Backtrace(find_current_map, nullptr);
}
@@ -98,7 +102,8 @@
}
// Do not record the frames that fall in our own shared library.
- if (g_current_code_map && (ip >= g_current_code_map->start) && ip < g_current_code_map->end) {
+ if (g_current_code_map.start() != 0 && (ip >= g_current_code_map.start()) &&
+ ip < g_current_code_map.end()) {
return _URC_NO_REASON;
}
@@ -113,6 +118,10 @@
}
std::string backtrace_string(const uintptr_t* frames, size_t frame_count) {
+ if (g_map_data.NumMaps() == 0) {
+ g_map_data.ReadMaps();
+ }
+
std::string str;
for (size_t frame_num = 0; frame_num < frame_count; frame_num++) {
@@ -130,14 +139,15 @@
uintptr_t rel_pc = offset;
const MapEntry* entry = g_map_data.find(frames[frame_num], &rel_pc);
- const char* soname = (entry != nullptr) ? entry->name.c_str() : info.dli_fname;
+ const char* soname = (entry != nullptr) ? entry->name().c_str() : info.dli_fname;
if (soname == nullptr) {
soname = "<unknown>";
}
char offset_buf[128];
- if (entry != nullptr && entry->elf_start_offset != 0) {
- snprintf(offset_buf, sizeof(offset_buf), " (offset 0x%" PRIxPTR ")", entry->elf_start_offset);
+ if (entry != nullptr && entry->elf_start_offset() != 0) {
+ snprintf(offset_buf, sizeof(offset_buf), " (offset 0x%" PRIxPTR ")",
+ entry->elf_start_offset());
} else {
offset_buf[0] = '\0';
}
@@ -167,5 +177,6 @@
}
void backtrace_log(const uintptr_t* frames, size_t frame_count) {
+ g_map_data.ReadMaps();
error_log_string(backtrace_string(frames, frame_count).c_str());
}
diff --git a/libc/platform/bionic/page.h b/libc/platform/bionic/page.h
index 65faba4..4dbe4ba 100644
--- a/libc/platform/bionic/page.h
+++ b/libc/platform/bionic/page.h
@@ -32,11 +32,13 @@
#endif
}
-constexpr size_t max_page_size() {
+// The maximum page size supported on any Android device. As
+// of API level 35, this is limited by ART.
+constexpr size_t max_android_page_size() {
#if defined(PAGE_SIZE)
return PAGE_SIZE;
#else
- return 65536;
+ return 16384;
#endif
}
diff --git a/libc/private/WriteProtected.h b/libc/private/WriteProtected.h
index bbe35e5..f269125 100644
--- a/libc/private/WriteProtected.h
+++ b/libc/private/WriteProtected.h
@@ -30,11 +30,11 @@
template <typename T>
union WriteProtectedContents {
T value;
- char padding[max_page_size()];
+ char padding[max_android_page_size()];
WriteProtectedContents() = default;
BIONIC_DISALLOW_COPY_AND_ASSIGN(WriteProtectedContents);
-} __attribute__((aligned(max_page_size())));
+} __attribute__((aligned(max_android_page_size())));
// Write protected wrapper class that aligns its contents to a page boundary,
// and sets the memory protection to be non-writable, except when being modified
@@ -42,8 +42,8 @@
template <typename T>
class WriteProtected {
public:
- static_assert(sizeof(T) < max_page_size(),
- "WriteProtected only supports contents up to max_page_size()");
+ static_assert(sizeof(T) < max_android_page_size(),
+ "WriteProtected only supports contents up to max_android_page_size()");
WriteProtected() = default;
BIONIC_DISALLOW_COPY_AND_ASSIGN(WriteProtected);
@@ -89,7 +89,7 @@
// ourselves.
addr = untag_address(addr);
#endif
- if (mprotect(reinterpret_cast<void*>(addr), max_page_size(), prot) == -1) {
+ if (mprotect(reinterpret_cast<void*>(addr), max_android_page_size(), prot) == -1) {
async_safe_fatal("WriteProtected mprotect %x failed: %s", prot, strerror(errno));
}
}
diff --git a/libdl/libdl_cfi.cpp b/libdl/libdl_cfi.cpp
index 23cd7f5..8adc342 100644
--- a/libdl/libdl_cfi.cpp
+++ b/libdl/libdl_cfi.cpp
@@ -26,15 +26,15 @@
// dlopen/dlclose.
static struct {
uintptr_t v;
- char padding[max_page_size() - sizeof(v)];
-} shadow_base_storage alignas(max_page_size());
+ char padding[max_android_page_size() - sizeof(v)];
+} shadow_base_storage alignas(max_android_page_size());
// __cfi_init is called by the loader as soon as the shadow is mapped. This may happen very early
// during startup, before libdl.so global constructors, and, on i386, even before __libc_sysinfo is
// initialized. This function should not do any system calls.
extern "C" uintptr_t* __cfi_init(uintptr_t shadow_base) {
shadow_base_storage.v = shadow_base;
- static_assert(sizeof(shadow_base_storage) == max_page_size(), "");
+ static_assert(sizeof(shadow_base_storage) == max_android_page_size(), "");
return &shadow_base_storage.v;
}
diff --git a/linker/Android.bp b/linker/Android.bp
index e1a5a91..1ede380 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -367,7 +367,9 @@
"liblinker_main",
"liblinker_malloc",
- "libc++_static",
+ // Use a version of libc++ built without exceptions, because accessing EH globals uses
+ // ELF TLS, which is not supported in the loader.
+ "libc++_static_noexcept",
"libc_nomalloc",
"libc_dynamic_dispatch",
"libm",
@@ -434,7 +436,7 @@
"linker_debuggerd_android.cpp",
],
static_libs: [
- "libc++demangle",
+ "libc++demangle_noexcept",
"libdebuggerd_handler_fallback",
],
},
diff --git a/tests/Android.bp b/tests/Android.bp
index 528ccb8..9aca488 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -1136,11 +1136,14 @@
shared_libs: [
"libbase",
],
- data_libs: ["libtest_simple_memtag_stack", "libtest_depends_on_simple_memtag_stack"],
+ data_libs: [
+ "libtest_simple_memtag_stack",
+ "libtest_depends_on_simple_memtag_stack",
+ ],
data_bins: [
"testbinary_depends_on_simple_memtag_stack",
"testbinary_depends_on_depends_on_simple_memtag_stack",
- "testbinary_is_stack_mte_after_dlopen"
+ "testbinary_is_stack_mte_after_dlopen",
],
header_libs: ["bionic_libc_platform_headers"],
test_suites: ["device-tests"],
@@ -1315,4 +1318,47 @@
},
}
-subdirs = ["*"]
+cc_defaults {
+ name: "bionic_compile_time_tests_defaults",
+ enabled: false,
+ target: {
+ linux_x86: {
+ enabled: true,
+ },
+ linux_x86_64: {
+ enabled: true,
+ },
+ },
+ tidy: false,
+ clang_verify: true,
+ cflags: [
+ "-Wall",
+ "-Wno-error",
+ "-fno-color-diagnostics",
+ "-ferror-limit=10000",
+ "-DCOMPILATION_TESTS=1",
+ "-Wformat-nonliteral",
+ "-U_FORTIFY_SOURCE",
+ ],
+ srcs: ["clang_fortify_tests.cpp"],
+}
+
+cc_library_static {
+ name: "bionic-compile-time-tests1-clang++",
+ defaults: [
+ "bionic_compile_time_tests_defaults",
+ ],
+ cppflags: [
+ "-D_FORTIFY_SOURCE=1",
+ ],
+}
+
+cc_library_static {
+ name: "bionic-compile-time-tests2-clang++",
+ defaults: [
+ "bionic_compile_time_tests_defaults",
+ ],
+ cppflags: [
+ "-D_FORTIFY_SOURCE=2",
+ ],
+}
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index 5ad4045..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Copyright (C) 2012 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
-
-# -----------------------------------------------------------------------------
-# Compile time tests.
-# -----------------------------------------------------------------------------
-
-FORTIFY_LEVEL := 1
-include $(LOCAL_PATH)/make_fortify_compile_test.mk
-
-FORTIFY_LEVEL := 2
-include $(LOCAL_PATH)/make_fortify_compile_test.mk
-
-endif # linux-x86
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/make_fortify_compile_test.mk b/tests/make_fortify_compile_test.mk
deleted file mode 100644
index ec0ba45..0000000
--- a/tests/make_fortify_compile_test.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-include $(CLEAR_VARS)
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(LOCAL_PATH)/Android.mk \
- $(LOCAL_PATH)/touch-obj-on-success
-
-LOCAL_CXX := $(LOCAL_PATH)/touch-obj-on-success \
- $(LLVM_PREBUILTS_PATH)/clang++ \
-
-LOCAL_CLANG := true
-LOCAL_MODULE := bionic-compile-time-tests$(FORTIFY_LEVEL)-clang++
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
-LOCAL_TIDY := false
-LOCAL_CPPFLAGS := -Wall -Wno-error
-LOCAL_CPPFLAGS += -fno-color-diagnostics -ferror-limit=10000 -Xclang -verify
-LOCAL_CPPFLAGS += -DCOMPILATION_TESTS=1 -Wformat-nonliteral
-LOCAL_CPPFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=$(FORTIFY_LEVEL)
-LOCAL_SRC_FILES := clang_fortify_tests.cpp
-
-include $(BUILD_STATIC_LIBRARY)
-
-FORTIFY_LEVEL :=