Merge "Assume clang's *LONG_LONG*_ macros." into main
diff --git a/libc/Android.bp b/libc/Android.bp
index 8407a60..5d1a2f2 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1085,7 +1085,6 @@
"arch-arm/kryo/bionic/memcpy.S",
"bionic/strchr.cpp",
- "bionic/strchrnul.cpp",
"bionic/strnlen.cpp",
],
},
@@ -1140,8 +1139,6 @@
"arch-riscv64/string/strncmp.c",
"arch-riscv64/string/strncpy.c",
"arch-riscv64/string/strnlen.c",
-
- "bionic/strchrnul.cpp",
],
},
@@ -1173,8 +1170,6 @@
"arch-x86/string/ssse3-strncmp-atom.S",
"arch-x86/string/sse4-memcmp-slm.S",
-
- "bionic/strchrnul.cpp",
],
},
x86_64: {
diff --git a/libc/bionic/strchrnul.cpp b/libc/bionic/strchrnul.cpp
deleted file mode 100644
index 55422e0..0000000
--- a/libc/bionic/strchrnul.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-extern "C" const char* strchrnul(const char* s, int ch) {
- while (*s && *s != ch) {
- ++s;
- }
- return s;
-}
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index c183897..a662529 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -1091,18 +1091,20 @@
void debug_malloc_disable() {
ScopedConcurrentLock lock;
- g_dispatch->malloc_disable();
if (g_debug->pointer) {
+ // Acquire the pointer locks first, otherwise, the code can be holding
+ // the allocation lock and deadlock trying to acquire a pointer lock.
g_debug->pointer->PrepareFork();
}
+ g_dispatch->malloc_disable();
}
void debug_malloc_enable() {
ScopedConcurrentLock lock;
+ g_dispatch->malloc_enable();
if (g_debug->pointer) {
g_debug->pointer->PostForkParent();
}
- g_dispatch->malloc_enable();
}
ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t max_frames) {
diff --git a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
index d7a7a4f..080242c 100644
--- a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp
@@ -57,6 +57,12 @@
#include <bionic/malloc.h>
#include <tests/utils.h>
+// exported from bionic
+__BEGIN_DECLS
+extern void malloc_disable();
+extern void malloc_enable();
+__END_DECLS
+
// All DISABLED_ tests are designed to be executed after malloc debug
// is enabled. These tests don't run be default, and are executed
// by wrappers that will enable various malloc debug features.
@@ -788,3 +794,34 @@
unexpected_log_strings_.push_back("Timed out waiting for ");
Exec("MallocTests.DISABLED_malloc_and_backtrace_deadlock", "verbose verify_pointers", 0);
}
+
+// Creates two threads: one that calls malloc_disable() and malloc_enable() in a loop and
+// the other that performs a bunch of allocations.
+TEST(MallocTests, DISABLED_malloc_disable_deadlock) {
+ std::atomic_bool running(true);
+
+ std::thread t1([&] {
+ while (running) {
+ malloc_disable();
+ malloc_enable();
+ }
+ });
+
+ std::thread t2([&] {
+ while (running) {
+ void* p = malloc(100);
+ free(p);
+ }
+ });
+
+ // let the threads run for a while, then tell them to stop and wait for shutdown
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+
+ running = false;
+ t1.join();
+ t2.join();
+}
+
+TEST_F(MallocDebugSystemTest, malloc_disable_deadlock) {
+ Exec("MallocTests.DISABLED_malloc_disable_deadlock", "verbose backtrace");
+}
diff --git a/libc/platform/bionic/macros.h b/libc/platform/bionic/macros.h
index b2d6f96..1e7ca88 100644
--- a/libc/platform/bionic/macros.h
+++ b/libc/platform/bionic/macros.h
@@ -16,6 +16,7 @@
#pragma once
+#include <stddef.h>
#include <stdint.h>
#define BIONIC_DISALLOW_COPY_AND_ASSIGN(TypeName) \
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index e5369ac..8bcd76c 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -159,8 +159,8 @@
ElfReader::ElfReader()
: did_read_(false), did_load_(false), fd_(-1), file_offset_(0), file_size_(0), phdr_num_(0),
phdr_table_(nullptr), shdr_table_(nullptr), shdr_num_(0), dynamic_(nullptr), strtab_(nullptr),
- strtab_size_(0), load_start_(nullptr), load_size_(0), load_bias_(0), loaded_phdr_(nullptr),
- mapped_by_caller_(false) {
+ strtab_size_(0), load_start_(nullptr), load_size_(0), load_bias_(0), max_align_(0), min_align_(0),
+ loaded_phdr_(nullptr), mapped_by_caller_(false) {
}
bool ElfReader::Read(const char* name, int fd, off64_t file_offset, off64_t file_size) {
@@ -175,13 +175,14 @@
if (ReadElfHeader() &&
VerifyElfHeader() &&
ReadProgramHeaders() &&
+ CheckProgramHeaderAlignment() &&
ReadSectionHeaders() &&
ReadDynamicSection() &&
ReadPadSegmentNote()) {
did_read_ = true;
}
- if (kPageSize == 0x4000 && phdr_table_get_minimum_alignment(phdr_table_, phdr_num_) == 0x1000) {
+ if (kPageSize == 16*1024 && min_align_ == 4096) {
// This prop needs to be read on 16KiB devices for each ELF where min_palign is 4KiB.
// It cannot be cached since the developer may toggle app compat on/off.
// This check will be removed once app compat is made the default on 16KiB devices.
@@ -562,52 +563,28 @@
return max_vaddr - min_vaddr;
}
-// Returns the maximum p_align associated with a loadable segment in the ELF
-// program header table. Used to determine whether the file should be loaded at
-// a specific virtual address alignment for use with huge pages.
-size_t phdr_table_get_maximum_alignment(const ElfW(Phdr)* phdr_table, size_t phdr_count) {
- size_t maximum_alignment = page_size();
+bool ElfReader::CheckProgramHeaderAlignment() {
+ max_align_ = min_align_ = page_size();
- for (size_t i = 0; i < phdr_count; ++i) {
- const ElfW(Phdr)* phdr = &phdr_table[i];
+ for (size_t i = 0; i < phdr_num_; ++i) {
+ const ElfW(Phdr)* phdr = &phdr_table_[i];
// p_align must be 0, 1, or a positive, integral power of two.
if (phdr->p_type != PT_LOAD || ((phdr->p_align & (phdr->p_align - 1)) != 0)) {
+ // TODO: reject ELF files with bad p_align values.
continue;
}
- maximum_alignment = std::max(maximum_alignment, static_cast<size_t>(phdr->p_align));
- }
-
-#if defined(__LP64__)
- return maximum_alignment;
-#else
- return page_size();
+#if defined(__LP64__) // TODO: remove this historical accident #if
+ max_align_ = std::max(max_align_, static_cast<size_t>(phdr->p_align));
#endif
-}
-// Returns the minimum p_align associated with a loadable segment in the ELF
-// program header table. Used to determine if the program alignment is compatible
-// with the page size of this system.
-size_t phdr_table_get_minimum_alignment(const ElfW(Phdr)* phdr_table, size_t phdr_count) {
- size_t minimum_alignment = page_size();
-
- for (size_t i = 0; i < phdr_count; ++i) {
- const ElfW(Phdr)* phdr = &phdr_table[i];
-
- // p_align must be 0, 1, or a positive, integral power of two.
- if (phdr->p_type != PT_LOAD || ((phdr->p_align & (phdr->p_align - 1)) != 0)) {
- continue;
+ if (phdr->p_align > 1) {
+ min_align_ = std::min(min_align_, static_cast<size_t>(phdr->p_align));
}
-
- if (phdr->p_align <= 1) {
- continue;
- }
-
- minimum_alignment = std::min(minimum_alignment, static_cast<size_t>(phdr->p_align));
}
- return minimum_alignment;
+ return true;
}
// Reserve a virtual address range such that if it's limits were extended to the next 2**align
@@ -628,7 +605,7 @@
// Minimum alignment of shared library gap. For efficiency, this should match the second level
// page size of the platform.
#if defined(__LP64__)
- constexpr size_t kGapAlignment = 1ul << 21; // 2MB
+ constexpr size_t kGapAlignment = 2 * 1024 * 1024;
#else
constexpr size_t kGapAlignment = 0;
#endif
@@ -717,10 +694,9 @@
}
size_t start_alignment = page_size();
if (get_transparent_hugepages_supported() && get_application_target_sdk_version() >= 31) {
- size_t maximum_alignment = phdr_table_get_maximum_alignment(phdr_table_, phdr_num_);
// Limit alignment to PMD size as other alignments reduce the number of
// bits available for ASLR for no benefit.
- start_alignment = maximum_alignment == kPmdSize ? kPmdSize : page_size();
+ start_alignment = max_align_ == kPmdSize ? kPmdSize : page_size();
}
start = ReserveWithAlignmentPadding(load_size_, kLibraryAlignment, start_alignment, &gap_start_,
&gap_size_);
@@ -1011,13 +987,12 @@
// are not 16KiB aligned.
size_t seg_align = should_use_16kib_app_compat_ ? kCompatPageSize : kPageSize;
- size_t min_palign = phdr_table_get_minimum_alignment(phdr_table_, phdr_num_);
// Only enforce this on 16 KB systems with app compat disabled.
// Apps may rely on undefined behavior here on 4 KB systems,
// which is the norm before this change is introduced
- if (kPageSize >= 16384 && min_palign < kPageSize && !should_use_16kib_app_compat_) {
+ if (kPageSize >= 16384 && min_align_ < kPageSize && !should_use_16kib_app_compat_) {
DL_ERR("\"%s\" program alignment (%zu) cannot be smaller than system page size (%zu)",
- name_.c_str(), min_palign, kPageSize);
+ name_.c_str(), min_align_, kPageSize);
return false;
}
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index e15ece4..3b68528 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -76,6 +76,7 @@
[[nodiscard]] bool ReadElfHeader();
[[nodiscard]] bool VerifyElfHeader();
[[nodiscard]] bool ReadProgramHeaders();
+ [[nodiscard]] bool CheckProgramHeaderAlignment();
[[nodiscard]] bool ReadSectionHeaders();
[[nodiscard]] bool ReadDynamicSection();
[[nodiscard]] bool ReadPadSegmentNote();
@@ -130,6 +131,10 @@
// Load bias.
ElfW(Addr) load_bias_;
+ // Maximum and minimum alignment requirements across all phdrs.
+ size_t max_align_;
+ size_t min_align_;
+
// Loaded phdr.
const ElfW(Phdr)* loaded_phdr_;
@@ -153,9 +158,6 @@
size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr)* min_vaddr = nullptr, ElfW(Addr)* max_vaddr = nullptr);
-size_t phdr_table_get_maximum_alignment(const ElfW(Phdr)* phdr_table, size_t phdr_count);
-size_t phdr_table_get_minimum_alignment(const ElfW(Phdr)* phdr_table, size_t phdr_count);
-
int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr) load_bias, bool should_pad_segments,
bool should_use_16kib_app_compat,