Merge changes I158862fd,Ieb9de996
* changes:
Removing clang_cflags to check if they're even necessary
Moved contents of clang_cflags into cflags
diff --git a/libc/SECCOMP_ALLOWLIST_COMMON.TXT b/libc/SECCOMP_ALLOWLIST_COMMON.TXT
index c440f9b..a4218ee 100644
--- a/libc/SECCOMP_ALLOWLIST_COMMON.TXT
+++ b/libc/SECCOMP_ALLOWLIST_COMMON.TXT
@@ -31,6 +31,8 @@
int open:open(const char*, int, ...) arm,x86,x86_64
int stat64:stat64(const char*, struct stat64*) arm,x86
ssize_t readlink:readlink(const char*, char*, size_t) arm,x86,x86_64
+# Needed by ubsan in T? (http://b/229989971)
+int stat(const char*, struct stat*) arm,x86,x86_64
#
# Useful new syscalls which we don't yet use in bionic.
@@ -74,5 +76,3 @@
int sched_rr_get_interval_time64(pid_t, timespec64*) lp32
# Since Linux 5.4, not in glibc. Probed for and conditionally used by ART.
int userfaultfd(int) all
-# Since Linux 5.9, used by POSIX_SPAWN_CLOEXEC_DEFAULT
-int close_range(unsigned int, unsigned int, int) all
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index a09c614..1435e79 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -107,6 +107,7 @@
ssize_t __pwritev64v2:pwritev2(int, const struct iovec*, int, long, long, int) all
int __close:close(int) all
+int close_range(unsigned int, unsigned int, int) all
pid_t __getpid:getpid() all
int memfd_create(const char*, unsigned) all
int munmap(void*, size_t) all
diff --git a/libc/bionic/spawn.cpp b/libc/bionic/spawn.cpp
index 59f7631..7e80ef6 100644
--- a/libc/bionic/spawn.cpp
+++ b/libc/bionic/spawn.cpp
@@ -52,7 +52,7 @@
// mark all open fds except stdin/out/err as close-on-exec
static int cloexec_except_stdioe() {
// requires 5.11+ or ACK 5.10-T kernel, otherwise returns ENOSYS or EINVAL
- if (!syscall(SYS_close_range, 3, ~0U, CLOSE_RANGE_CLOEXEC)) return 0;
+ if (!close_range(3, ~0U, CLOSE_RANGE_CLOEXEC)) return 0;
// unfortunately getrlimit can lie:
// - both soft and hard limits can be lowered to 0, with fds still open, so it can underestimate
diff --git a/libc/include/android/legacy_stdlib_inlines.h b/libc/include/android/legacy_stdlib_inlines.h
index aeb1575..6903536 100644
--- a/libc/include/android/legacy_stdlib_inlines.h
+++ b/libc/include/android/legacy_stdlib_inlines.h
@@ -57,13 +57,11 @@
__BEGIN_DECLS
static __inline float strtof(const char* nptr, char** endptr) {
+ // N.B. Double-rounding makes this function incorrect for some inputs.
double d = strtod(nptr, endptr);
- if (d > FLT_MAX) {
+ if (__builtin_isfinite(d) && __builtin_fabs(d) > FLT_MAX) {
errno = ERANGE;
- return __builtin_huge_valf();
- } else if (d < -FLT_MAX) {
- errno = ERANGE;
- return -__builtin_huge_valf();
+ return __builtin_copysign(__builtin_huge_valf(), d);
}
return __BIONIC_CAST(static_cast, float, d);
}
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index e360421..f142525 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -317,6 +317,22 @@
void swab(const void* __src, void* __dst, ssize_t __byte_count) __INTRODUCED_IN(28);
#endif
+/**
+ * [close_range(2)](https://man7.org/linux/man-pages/man2/close_range.2.html)
+ * performs an action (which depends on value of flags) on an inclusive range
+ * of file descriptors.
+ *
+ * Available since API level 34.
+ *
+ * Note: there is no emulation on too old kernels, hence this will fail with
+ * -1/ENOSYS on pre-5.9 kernels, -1/EINVAL for unsupported flags. In particular
+ * CLOSE_RANGE_CLOEXEC requires 5.11, though support was backported to Android
+ * Common Kernel 5.10-T.
+ *
+ * Returns 0 on success, and returns -1 and sets `errno` on failure.
+ */
+int close_range(unsigned int __min_fd, unsigned int __max_fd, int __flags) __INTRODUCED_IN(34);
+
#if defined(__BIONIC_INCLUDE_FORTIFY_HEADERS)
#define _UNISTD_H_
#include <bits/fortify/unistd.h>
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 7397b68..e64fe00 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1576,6 +1576,11 @@
pwritev64v2;
} LIBC_S;
+LIBC_U { # introduced=UpsideDownCake
+ global:
+ close_range;
+} LIBC_T;
+
LIBC_PRIVATE {
global:
__accept4; # arm x86
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
index b982c0a..eaa0eb7 100644
--- a/libc/malloc_debug/PointerData.cpp
+++ b/libc/malloc_debug/PointerData.cpp
@@ -35,6 +35,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <functional>
#include <mutex>
#include <string>
#include <unordered_map>
@@ -195,40 +196,41 @@
}
void PointerData::Add(const void* ptr, size_t pointer_size) {
- uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
size_t hash_index = 0;
if (backtrace_enabled_) {
hash_index = AddBacktrace(g_debug->config().backtrace_frames());
}
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
- pointers_[pointer] = PointerInfoType{PointerInfoType::GetEncodedSize(pointer_size), hash_index};
+ uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
+ pointers_[mangled_ptr] =
+ PointerInfoType{PointerInfoType::GetEncodedSize(pointer_size), hash_index};
}
void PointerData::Remove(const void* ptr) {
- uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
size_t hash_index;
{
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
- auto entry = pointers_.find(pointer);
+ uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
+ auto entry = pointers_.find(mangled_ptr);
if (entry == pointers_.end()) {
// Attempt to remove unknown pointer.
- error_log("No tracked pointer found for 0x%" PRIxPTR, pointer);
+ error_log("No tracked pointer found for 0x%" PRIxPTR, DemanglePointer(mangled_ptr));
return;
}
hash_index = entry->second.hash_index;
- pointers_.erase(pointer);
+ pointers_.erase(mangled_ptr);
}
RemoveBacktrace(hash_index);
}
size_t PointerData::GetFrames(const void* ptr, uintptr_t* frames, size_t max_frames) {
- uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
size_t hash_index;
{
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
- auto entry = pointers_.find(pointer);
+ uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
+ auto entry = pointers_.find(mangled_ptr);
if (entry == pointers_.end()) {
return 0;
}
@@ -274,7 +276,8 @@
void PointerData::LogFreeError(const FreePointerInfoType& info, size_t max_cmp_bytes) {
error_log(LOG_DIVIDER);
- uint8_t* memory = reinterpret_cast<uint8_t*>(info.pointer);
+ uintptr_t pointer = DemanglePointer(info.mangled_ptr);
+ uint8_t* memory = reinterpret_cast<uint8_t*>(pointer);
error_log("+++ ALLOCATION %p USED AFTER FREE", memory);
uint8_t fill_free_value = g_debug->config().fill_free_value();
for (size_t i = 0; i < max_cmp_bytes; i++) {
@@ -296,13 +299,14 @@
void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
size_t usable_size;
+ uintptr_t pointer = DemanglePointer(info.mangled_ptr);
if (g_debug->HeaderEnabled()) {
// Check to see if the tag data has been damaged.
- Header* header = g_debug->GetHeader(reinterpret_cast<const void*>(info.pointer));
+ Header* header = g_debug->GetHeader(reinterpret_cast<const void*>(pointer));
if (header->tag != DEBUG_FREE_TAG) {
error_log(LOG_DIVIDER);
- error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE",
- info.pointer, header->tag);
+ error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE", pointer,
+ header->tag);
error_log(LOG_DIVIDER);
if (g_debug->config().options() & ABORT_ON_ERROR) {
abort();
@@ -314,14 +318,14 @@
}
usable_size = header->usable_size;
} else {
- usable_size = g_dispatch->malloc_usable_size(reinterpret_cast<const void*>(info.pointer));
+ usable_size = g_dispatch->malloc_usable_size(reinterpret_cast<const void*>(pointer));
}
size_t bytes = (usable_size < g_debug->config().fill_on_free_bytes())
? usable_size
: g_debug->config().fill_on_free_bytes();
size_t max_cmp_bytes = bytes;
- const uint8_t* memory = reinterpret_cast<const uint8_t*>(info.pointer);
+ const uint8_t* memory = reinterpret_cast<const uint8_t*>(pointer);
while (bytes > 0) {
size_t bytes_to_cmp = (bytes < g_cmp_mem.size()) ? bytes : g_cmp_mem.size();
if (memcmp(memory, g_cmp_mem.data(), bytes_to_cmp) != 0) {
@@ -333,8 +337,6 @@
}
void* PointerData::AddFreed(const void* ptr) {
- uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
-
size_t hash_index = 0;
size_t num_frames = g_debug->config().free_track_backtrace_num_frames();
if (num_frames) {
@@ -348,10 +350,11 @@
free_pointers_.pop_front();
VerifyFreedPointer(info);
RemoveBacktrace(info.hash_index);
- last = reinterpret_cast<void*>(info.pointer);
+ last = reinterpret_cast<void*>(DemanglePointer(info.mangled_ptr));
}
- free_pointers_.emplace_back(FreePointerInfoType{pointer, hash_index});
+ uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
+ free_pointers_.emplace_back(FreePointerInfoType{mangled_ptr, hash_index});
return last;
}
@@ -361,7 +364,7 @@
uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
for (const auto& info : free_pointers_) {
- if (info.pointer == pointer) {
+ if (DemanglePointer(info.mangled_ptr) == pointer) {
hash_index = info.hash_index;
break;
}
@@ -388,6 +391,7 @@
for (const auto& entry : pointers_) {
FrameInfoType* frame_info = nullptr;
std::vector<unwindstack::FrameData>* backtrace_info = nullptr;
+ uintptr_t pointer = DemanglePointer(entry.first);
size_t hash_index = entry.second.hash_index;
if (hash_index > kBacktraceEmptyIndex) {
auto frame_entry = frames_.find(hash_index);
@@ -397,7 +401,7 @@
// occurs after the hash_index and frame data have been added.
// When removing a pointer, the pointer is deleted before the frame
// data.
- error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
+ error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", pointer, hash_index);
} else {
frame_info = &frame_entry->second;
}
@@ -405,7 +409,7 @@
if (g_debug->config().options() & BACKTRACE_FULL) {
auto backtrace_entry = backtraces_info_.find(hash_index);
if (backtrace_entry == backtraces_info_.end()) {
- error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
+ error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", pointer, hash_index);
} else {
backtrace_info = &backtrace_entry->second;
}
@@ -415,7 +419,7 @@
continue;
}
- list->emplace_back(ListInfoType{entry.first, 1, entry.second.RealSize(),
+ list->emplace_back(ListInfoType{pointer, 1, entry.second.RealSize(),
entry.second.ZygoteChildAlloc(), frame_info, backtrace_info});
}
@@ -550,9 +554,9 @@
}
bool PointerData::Exists(const void* ptr) {
- uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
- return pointers_.count(pointer) != 0;
+ uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
+ return pointers_.count(mangled_ptr) != 0;
}
void PointerData::DumpLiveToFile(int fd) {
@@ -637,3 +641,10 @@
free_pointer_mutex_.try_lock();
free_pointer_mutex_.unlock();
}
+
+void PointerData::IteratePointers(std::function<void(uintptr_t pointer)> fn) {
+ std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
+ for (const auto entry : pointers_) {
+ fn(DemanglePointer(entry.first));
+ }
+}
diff --git a/libc/malloc_debug/PointerData.h b/libc/malloc_debug/PointerData.h
index 92d2653..97eec0a 100644
--- a/libc/malloc_debug/PointerData.h
+++ b/libc/malloc_debug/PointerData.h
@@ -33,6 +33,7 @@
#include <atomic>
#include <deque>
+#include <functional>
#include <mutex>
#include <string>
#include <unordered_map>
@@ -99,7 +100,7 @@
};
struct FreePointerInfoType {
- uintptr_t pointer;
+ uintptr_t mangled_ptr;
size_t hash_index;
};
@@ -134,16 +135,14 @@
void PostForkParent();
void PostForkChild();
+ static void IteratePointers(std::function<void(uintptr_t pointer)> fn);
+
static size_t AddBacktrace(size_t num_frames);
static void RemoveBacktrace(size_t hash_index);
static void Add(const void* pointer, size_t size);
static void Remove(const void* pointer);
- typedef std::unordered_map<uintptr_t, PointerInfoType>::iterator iterator;
- static iterator begin() { return pointers_.begin(); }
- static iterator end() { return pointers_.end(); }
-
static void* AddFreed(const void* pointer);
static void LogFreeError(const FreePointerInfoType& info, size_t usable_size);
static void LogFreeBacktrace(const void* ptr);
@@ -162,6 +161,12 @@
static bool Exists(const void* pointer);
private:
+ // Only keep mangled pointers in internal data structures. This avoids
+ // problems where libmemunreachable finds these pointers and thinks they
+ // are not unreachable.
+ static inline uintptr_t ManglePointer(uintptr_t pointer) { return pointer ^ UINTPTR_MAX; }
+ static inline uintptr_t DemanglePointer(uintptr_t pointer) { return pointer ^ UINTPTR_MAX; }
+
static std::string GetHashString(uintptr_t* frames, size_t num_frames);
static void LogBacktrace(size_t hash_index);
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 9f38946..d608f5d 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -890,10 +890,9 @@
void* arg) {
ScopedConcurrentLock lock;
if (g_debug->TrackPointers()) {
- // Since malloc is disabled, don't bother acquiring any locks.
- for (auto it = PointerData::begin(); it != PointerData::end(); ++it) {
- callback(it->first, InternalMallocUsableSize(reinterpret_cast<void*>(it->first)), arg);
- }
+ PointerData::IteratePointers([&callback, &arg](uintptr_t pointer) {
+ callback(pointer, InternalMallocUsableSize(reinterpret_cast<void*>(pointer)), arg);
+ });
return 0;
}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 6d7e687..293b45a 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -1648,3 +1648,23 @@
auto t1 = std::chrono::steady_clock::now();
ASSERT_GE(t1-t0, 1s);
}
+
+TEST(UNISTD_TEST, close_range) {
+#if defined(__GLIBC__)
+ GTEST_SKIP() << "glibc too old";
+#else // __GLIBC__
+ int fd = open("/proc/version", O_RDONLY);
+ ASSERT_GE(fd, 0);
+
+ // Try to close the file descriptor (this requires a 5.9+ kernel)
+ if (close_range(fd, fd, 0) == 0) {
+ // we can't close it *again*
+ ASSERT_EQ(close(fd), -1);
+ ASSERT_EQ(errno, EBADF);
+ } else {
+ ASSERT_EQ(errno, ENOSYS);
+ // since close_range() failed, we can close it normally
+ ASSERT_EQ(close(fd), 0);
+ }
+#endif // __GLIBC__
+}