Merge "pthread_exit(): reduce duplication." into main
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 888404c..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
diff --git a/libc/bionic/bionic_allocator.cpp b/libc/bionic/bionic_allocator.cpp
index 80e8b08..41baf8b 100644
--- a/libc/bionic/bionic_allocator.cpp
+++ b/libc/bionic/bionic_allocator.cpp
@@ -299,7 +299,7 @@
log2_size = kSmallObjectMinSizeLog2;
}
- return get_small_object_allocator(log2_size)->alloc();
+ return get_small_object_allocator_unchecked(log2_size)->alloc();
}
void* BionicAllocator::alloc(size_t size) {
@@ -330,9 +330,10 @@
inline page_info* BionicAllocator::get_page_info(void* ptr) {
page_info* info = get_page_info_unchecked(ptr);
if (memcmp(info->signature, kSignature, sizeof(kSignature)) != 0) {
- async_safe_fatal("invalid pointer %p (page signature mismatch)", ptr);
+ async_safe_fatal("invalid pointer %p (page signature %04x instead of %04x)", ptr,
+ *reinterpret_cast<const unsigned*>(info->signature),
+ *reinterpret_cast<const unsigned*>(kSignature));
}
-
return info;
}
@@ -353,12 +354,7 @@
if (info->type == kLargeObject) {
old_size = info->allocated_size - (static_cast<char*>(ptr) - reinterpret_cast<char*>(info));
} else {
- BionicSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
- if (allocator != info->allocator_addr) {
- async_safe_fatal("invalid pointer %p (page signature mismatch)", ptr);
- }
-
- old_size = allocator->get_block_size();
+ old_size = get_small_object_allocator(info, ptr)->get_block_size();
}
if (old_size < size) {
@@ -377,16 +373,10 @@
}
page_info* info = get_page_info(ptr);
-
if (info->type == kLargeObject) {
munmap(info, info->allocated_size);
} else {
- BionicSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
- if (allocator != info->allocator_addr) {
- async_safe_fatal("invalid pointer %p (invalid allocator address for the page)", ptr);
- }
-
- allocator->free(ptr);
+ get_small_object_allocator(info, ptr)->free(ptr);
}
}
@@ -402,7 +392,7 @@
return info->allocated_size - (static_cast<char*>(ptr) - reinterpret_cast<char*>(info));
}
- BionicSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
+ BionicSmallObjectAllocator* allocator = get_small_object_allocator_unchecked(info->type);
if (allocator != info->allocator_addr) {
// Invalid pointer.
return 0;
@@ -410,7 +400,7 @@
return allocator->get_block_size();
}
-BionicSmallObjectAllocator* BionicAllocator::get_small_object_allocator(uint32_t type) {
+BionicSmallObjectAllocator* BionicAllocator::get_small_object_allocator_unchecked(uint32_t type) {
if (type < kSmallObjectMinSizeLog2 || type > kSmallObjectMaxSizeLog2) {
async_safe_fatal("invalid type: %u", type);
}
@@ -418,3 +408,11 @@
initialize_allocators();
return &allocators_[type - kSmallObjectMinSizeLog2];
}
+
+BionicSmallObjectAllocator* BionicAllocator::get_small_object_allocator(page_info* pi, void* ptr) {
+ BionicSmallObjectAllocator* result = get_small_object_allocator_unchecked(pi->type);
+ if (result != pi->allocator_addr) {
+ async_safe_fatal("invalid pointer %p (invalid allocator address for the page)", ptr);
+ }
+ return result;
+}
\ No newline at end of file
diff --git a/libc/bionic/bionic_elf_tls.cpp b/libc/bionic/bionic_elf_tls.cpp
index a053c27..3245b90 100644
--- a/libc/bionic/bionic_elf_tls.cpp
+++ b/libc/bionic/bionic_elf_tls.cpp
@@ -400,9 +400,10 @@
// segment.
//
// On most targets, this accessor function is __tls_get_addr and
-// TLS_GET_ADDR_CCONV is unset. 32-bit x86 uses ___tls_get_addr instead and a
-// regparm() calling convention.
-extern "C" void* TLS_GET_ADDR(const TlsIndex* ti) TLS_GET_ADDR_CCONV {
+// TLS_GET_ADDR_CALLING_CONVENTION is unset, but 32-bit x86 uses
+// ___tls_get_addr (with three underscores) instead, and a regparm
+// calling convention.
+extern "C" void* TLS_GET_ADDR(const TlsIndex* ti) TLS_GET_ADDR_CALLING_CONVENTION {
TlsDtv* dtv = __get_tcb_dtv(__get_bionic_tcb());
// TODO: See if we can use a relaxed memory ordering here instead.
diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp
index c8a025f..cadab3c 100644
--- a/libc/bionic/heap_tagging.cpp
+++ b/libc/bionic/heap_tagging.cpp
@@ -34,6 +34,7 @@
#include <platform/bionic/malloc.h>
#include <sanitizer/hwasan_interface.h>
#include <sys/auxv.h>
+#include <sys/prctl.h>
extern "C" void scudo_malloc_disable_memory_tagging();
extern "C" void scudo_malloc_set_track_allocation_stacks(int);
diff --git a/libc/bionic/malloc_limit.cpp b/libc/bionic/malloc_limit.cpp
index deb63f4..5128a35 100644
--- a/libc/bionic/malloc_limit.cpp
+++ b/libc/bionic/malloc_limit.cpp
@@ -31,6 +31,7 @@
#include <stdatomic.h>
#include <stdint.h>
#include <stdio.h>
+#include <unistd.h>
#include <private/bionic_malloc_dispatch.h>
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/bionic/sys_thread_properties.cpp b/libc/bionic/sys_thread_properties.cpp
index d7188f5..064bca1 100644
--- a/libc/bionic/sys_thread_properties.cpp
+++ b/libc/bionic/sys_thread_properties.cpp
@@ -61,7 +61,7 @@
if (modules.first_thread_exit_callback == nullptr) {
modules.first_thread_exit_callback = cb;
return;
- };
+ }
BionicAllocator& allocator = __libc_shared_globals()->tls_allocator;
CallbackHolder* new_node =
diff --git a/libc/bionic/wcwidth.cpp b/libc/bionic/wcwidth.cpp
index 9676b5a..4582ef7 100644
--- a/libc/bionic/wcwidth.cpp
+++ b/libc/bionic/wcwidth.cpp
@@ -52,12 +52,15 @@
return -1;
case U_NON_SPACING_MARK:
case U_ENCLOSING_MARK:
- case U_FORMAT_CHAR:
return 0;
+ case U_FORMAT_CHAR:
+ // A special case for soft hyphen (U+00AD) to match historical practice.
+ // See the tests for more commentary.
+ return (wc == 0x00ad) ? 1 : 0;
}
- if (__icu_hasBinaryProperty(wc, UCHAR_DEFAULT_IGNORABLE_CODE_POINT, nullptr)) return 0;
- // Medial and final jamo render as zero width when used correctly.
+ // Medial and final jamo render as zero width when used correctly,
+ // so we handle them specially rather than relying on East Asian Width.
switch (__icu_getIntPropertyValue(wc, UCHAR_HANGUL_SYLLABLE_TYPE)) {
case U_HST_VOWEL_JAMO:
case U_HST_TRAILING_JAMO:
@@ -68,6 +71,11 @@
return 2;
}
+ // Hangeul choseong filler U+115F is default ignorable, so we check default
+ // ignorability only after we've already handled Hangeul jamo above.
+ if (__icu_hasBinaryProperty(wc, UCHAR_DEFAULT_IGNORABLE_CODE_POINT, nullptr)) return 0;
+
+ // A few weird special cases where EastAsianWidth is not helpful for us.
if (wc >= 0x3248 && wc <= 0x4dff) {
// Circled two-digit CJK "speed sign" numbers. EastAsianWidth is ambiguous,
// but wide makes more sense.
@@ -77,6 +85,7 @@
}
// The EastAsianWidth property is at least defined by the Unicode standard!
+ // https://www.unicode.org/reports/tr11/
switch (__icu_getIntPropertyValue(wc, UCHAR_EAST_ASIAN_WIDTH)) {
case U_EA_AMBIGUOUS:
case U_EA_HALFWIDTH:
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/libc/private/bionic_allocator.h b/libc/private/bionic_allocator.h
index 342fd51..9872669 100644
--- a/libc/private/bionic_allocator.h
+++ b/libc/private/bionic_allocator.h
@@ -28,13 +28,9 @@
#pragma once
-#include <errno.h>
-#include <stdlib.h>
#include <sys/cdefs.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
#include <stddef.h>
-#include <unistd.h>
+#include <stdint.h>
const uint32_t kSmallObjectMaxSizeLog2 = 10;
const uint32_t kSmallObjectMinSizeLog2 = 4;
@@ -120,7 +116,8 @@
inline void* alloc_impl(size_t align, size_t size);
inline page_info* get_page_info_unchecked(void* ptr);
inline page_info* get_page_info(void* ptr);
- BionicSmallObjectAllocator* get_small_object_allocator(uint32_t type);
+ BionicSmallObjectAllocator* get_small_object_allocator_unchecked(uint32_t type);
+ BionicSmallObjectAllocator* get_small_object_allocator(page_info* pi, void* ptr);
void initialize_allocators();
BionicSmallObjectAllocator* allocators_;
diff --git a/libc/private/bionic_elf_tls.h b/libc/private/bionic_elf_tls.h
index 3a7b381..8bd5bc5 100644
--- a/libc/private/bionic_elf_tls.h
+++ b/libc/private/bionic_elf_tls.h
@@ -214,14 +214,14 @@
};
#if defined(__i386__)
-#define TLS_GET_ADDR_CCONV __attribute__((regparm(1)))
+#define TLS_GET_ADDR_CALLING_CONVENTION __attribute__((regparm(1)))
#define TLS_GET_ADDR ___tls_get_addr
#else
-#define TLS_GET_ADDR_CCONV
+#define TLS_GET_ADDR_CALLING_CONVENTION
#define TLS_GET_ADDR __tls_get_addr
#endif
-extern "C" void* TLS_GET_ADDR(const TlsIndex* ti) TLS_GET_ADDR_CCONV;
+extern "C" void* TLS_GET_ADDR(const TlsIndex* ti) TLS_GET_ADDR_CALLING_CONVENTION;
struct bionic_tcb;
void __free_dynamic_tls(bionic_tcb* tcb);
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/linker/linker_main.cpp b/linker/linker_main.cpp
index e27fd91..2b230a8 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -31,6 +31,7 @@
#include <link.h>
#include <stdlib.h>
#include <sys/auxv.h>
+#include <sys/prctl.h>
#include "linker.h"
#include "linker_auxv.h"
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 :=
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 5256b08..387d23b 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -1075,10 +1075,39 @@
EXPECT_EQ(0, wcwidth(0x0300)); // Combining grave.
EXPECT_EQ(0, wcwidth(0x20dd)); // Combining enclosing circle.
- EXPECT_EQ(0, wcwidth(0x00ad)); // Soft hyphen (SHY).
EXPECT_EQ(0, wcwidth(0x200b)); // Zero width space.
}
+TEST(wchar, wcwidth_non_spacing_special_cases) {
+ if (!have_dl()) return;
+
+ // U+00AD is a soft hyphen, which normally shouldn't be rendered at all.
+ // I think the assumption here is that you elide the soft hyphen character
+ // completely in that case, and never call wcwidth() if you don't want to
+ // render it as an actual hyphen. Whereas if you do want to render it,
+ // you call wcwidth(), and 1 is the right answer. This is what Markus Kuhn's
+ // original https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c did,
+ // and glibc and iOS do the same.
+ // See also: https://en.wikipedia.org/wiki/Soft_hyphen#Text_to_be_formatted_by_the_recipient
+ EXPECT_EQ(1, wcwidth(0x00ad)); // Soft hyphen (SHY).
+
+ // U+115F is the Hangeul choseong filler (for a degenerate composed
+ // character missing an initial consonant (as opposed to one with a
+ // leading ieung). Since the code points for combining jungseong (medial
+ // vowels) and jongseong (trailing consonants) have width 0, the choseong
+ // (initial consonant) has width 2 to cover the entire syllable. So unless
+ // U+115f has width 2, a degenerate composed "syllable" without an initial
+ // consonant or ieung would have a total width of 0, which is silly.
+ // The following sequence is effectively "약" without the leading ieung...
+ EXPECT_EQ(2, wcwidth(0x115f)); // Hangeul choseong filler.
+ EXPECT_EQ(0, wcwidth(0x1163)); // Hangeul jungseong "ya".
+ EXPECT_EQ(0, wcwidth(0x11a8)); // Hangeul jongseong "kiyeok".
+
+ // U+1160, the jungseong filler, has width 0 because it must have been
+ // preceded by either a choseong or choseong filler.
+ EXPECT_EQ(0, wcwidth(0x1160));
+}
+
TEST(wchar, wcwidth_cjk) {
if (!have_dl()) return;
@@ -1102,8 +1131,10 @@
if (!have_dl()) return;
EXPECT_EQ(2, wcwidth(0xac00)); // Start of block.
- EXPECT_EQ(2, wcwidth(0xd7a3)); // End of defined code points in Unicode 7.
- // Undefined characters at the end of the block have width 1.
+ EXPECT_EQ(2, wcwidth(0xd7a3)); // End of defined code points as of Unicode 15.
+
+ // Undefined characters at the end of the block currently have width 1,
+ // but since they're undefined, we don't test that.
}
TEST(wchar, wcwidth_kana) {
@@ -1137,11 +1168,21 @@
EXPECT_EQ(0, wcwidth(0xe0000)); // ...through 0xe0fff.
}
-TEST(wchar, wcwidth_korean_common_non_syllables) {
+TEST(wchar, wcwidth_hangeul_compatibility_jamo) {
if (!have_dl()) return;
- EXPECT_EQ(2, wcwidth(L'ㅜ')); // Korean "crying" emoticon.
- EXPECT_EQ(2, wcwidth(L'ㅋ')); // Korean "laughing" emoticon.
+ // These are actually the *compatibility* jamo code points, *not* the regular
+ // jamo code points (U+1100-U+11FF) using a jungseong filler. If you use the
+ // Android IME to type any of these, you get these code points.
+
+ // (Half of) the Korean "crying" emoticon "ㅠㅠ".
+ // Actually U+3160 "Hangeul Letter Yu" from Hangeul Compatibility Jamo.
+ EXPECT_EQ(2, wcwidth(L'ㅠ'));
+ // The two halves of the Korean internet shorthand "ㄱㅅ" (short for 감사).
+ // Actually U+3131 "Hangeul Letter Kiyeok" and U+3145 "Hangeul Letter Sios"
+ // from Hangeul Compatibility Jamo.
+ EXPECT_EQ(2, wcwidth(L'ㄱ'));
+ EXPECT_EQ(2, wcwidth(L'ㅅ'));
}
TEST(wchar, wcswidth) {