Merge "bionic: max_android_page_size to 16384" into main
diff --git a/benchmarks/linker_relocation/include/linker_reloc_bench_asm.h b/benchmarks/linker_relocation/include/linker_reloc_bench_asm.h
index 885e47f..ea63e36 100644
--- a/benchmarks/linker_relocation/include/linker_reloc_bench_asm.h
+++ b/benchmarks/linker_relocation/include/linker_reloc_bench_asm.h
@@ -44,9 +44,7 @@
#elif defined(__riscv)
-// No `lga` in clang unless https://reviews.llvm.org/D107278 lands.
-// `la` is equivalent when using PIC (which we do) though.
-#define GOT_RELOC(sym) la a0, sym
+#define GOT_RELOC(sym) lga a0, sym
#define CALL(sym) call sym@plt
#define DATA_WORD(val) .quad val
#define MAIN .globl main; main: li a0, 0; ret
diff --git a/benchmarks/util.h b/benchmarks/util.h
index 99eed5f..347dc35 100644
--- a/benchmarks/util.h
+++ b/benchmarks/util.h
@@ -71,7 +71,7 @@
bool LockToCPU(int cpu_to_lock);
-static __inline __attribute__ ((__always_inline__)) void MakeAllocationResident(
+static inline __attribute__((__always_inline__)) void MakeAllocationResident(
void* ptr, size_t nbytes, int pagesize) {
uint8_t* data = reinterpret_cast<uint8_t*>(ptr);
for (size_t i = 0; i < nbytes; i += pagesize) {
diff --git a/libc/bionic/execinfo.cpp b/libc/bionic/execinfo.cpp
index d129f7c..e53a037 100644
--- a/libc/bionic/execinfo.cpp
+++ b/libc/bionic/execinfo.cpp
@@ -73,6 +73,11 @@
#elif defined(__aarch64__)
// All instructions are 4 bytes long, skip back one instruction.
ip -= 4;
+#elif defined(__riscv)
+ // C instructions are the shortest at 2 bytes long. (Unlike thumb, it's
+ // non-trivial to recognize C instructions when going backwards in the
+ // instruction stream.)
+ ip -= 2;
#elif defined(__i386__) || defined(__x86_64__)
// It's difficult to decode exactly where the previous instruction is,
// so subtract 1 to estimate where the instruction lives.
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index d86df30..3da0a92 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -297,6 +297,30 @@
return level;
}
+static int64_t __get_memtag_upgrade_secs() {
+ char* env = getenv("BIONIC_MEMTAG_UPGRADE_SECS");
+ if (!env) return 0;
+ int64_t timed_upgrade = 0;
+ static const char kAppProcessName[] = "app_process64";
+ const char* progname = __libc_shared_globals()->init_progname;
+ progname = progname ? __gnu_basename(progname) : nullptr;
+ // disable timed upgrade for zygote, as the thread spawned will violate the requirement
+ // that it be single-threaded.
+ if (!progname || strncmp(progname, kAppProcessName, sizeof(kAppProcessName)) != 0) {
+ char* endptr;
+ timed_upgrade = strtoll(env, &endptr, 10);
+ if (*endptr != '\0' || timed_upgrade < 0) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "Invalid value for BIONIC_MEMTAG_UPGRADE_SECS: %s", env);
+ timed_upgrade = 0;
+ }
+ }
+ // Make sure that this does not get passed to potential processes inheriting
+ // this environment.
+ unsetenv("BIONIC_MEMTAG_UPGRADE_SECS");
+ return timed_upgrade;
+}
+
// Figure out the desired memory tagging mode (sync/async, heap/globals/stack) for this executable.
// This function is called from the linker before the main executable is relocated.
__attribute__((no_sanitize("hwaddress", "memtag"))) void __libc_init_mte(
@@ -313,31 +337,7 @@
}
memtag_stack = true;
}
- char* env = getenv("BIONIC_MEMTAG_UPGRADE_SECS");
- static const char kAppProcessName[] = "app_process64";
- const char* progname = __libc_shared_globals()->init_progname;
- progname = progname ? __gnu_basename(progname) : nullptr;
- if (progname &&
- strncmp(progname, kAppProcessName, sizeof(kAppProcessName)) == 0) {
- // disable timed upgrade for zygote, as the thread spawned will violate the requirement
- // that it be single-threaded.
- env = nullptr;
- }
- int64_t timed_upgrade = 0;
- if (env) {
- char* endptr;
- timed_upgrade = strtoll(env, &endptr, 10);
- if (*endptr != '\0' || timed_upgrade < 0) {
- async_safe_format_log(ANDROID_LOG_ERROR, "libc",
- "Invalid value for BIONIC_MEMTAG_UPGRADE_SECS: %s",
- env);
- timed_upgrade = 0;
- }
- // Make sure that this does not get passed to potential processes inheriting
- // this environment.
- unsetenv("BIONIC_MEMTAG_UPGRADE_SECS");
- }
- if (timed_upgrade) {
+ if (int64_t timed_upgrade = __get_memtag_upgrade_secs()) {
if (level == M_HEAP_TAGGING_LEVEL_ASYNC) {
async_safe_format_log(ANDROID_LOG_INFO, "libc",
"Attempting timed MTE upgrade from async to sync.");
diff --git a/libc/bionic/posix_timers.cpp b/libc/bionic/posix_timers.cpp
index f522516..ccbbfcf 100644
--- a/libc/bionic/posix_timers.cpp
+++ b/libc/bionic/posix_timers.cpp
@@ -34,6 +34,8 @@
#include <string.h>
#include <time.h>
+#include "private/bionic_lock.h"
+
// System calls.
extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t);
extern "C" int __rt_sigtimedwait(const sigset64_t*, siginfo_t*, const timespec*, size_t);
@@ -60,6 +62,7 @@
int sigev_notify;
// The fields below are only needed for a SIGEV_THREAD timer.
+ Lock startup_handshake_lock;
pthread_t callback_thread;
void (*callback)(sigval_t);
sigval_t callback_argument;
@@ -73,6 +76,18 @@
static void* __timer_thread_start(void* arg) {
PosixTimer* timer = reinterpret_cast<PosixTimer*>(arg);
+ // Check that our parent managed to create the kernel timer and bail if not...
+ timer->startup_handshake_lock.lock();
+ if (timer->kernel_timer_id == -1) {
+ free(timer);
+ return nullptr;
+ }
+
+ // Give ourselves a specific meaningful name now we have a kernel timer.
+ char name[16]; // 16 is the kernel-imposed limit.
+ snprintf(name, sizeof(name), "POSIX timer %d", to_kernel_timer_id(timer));
+ pthread_setname_np(timer->callback_thread, name);
+
sigset64_t sigset = {};
sigaddset64(&sigset, TIMER_SIGNAL);
@@ -109,6 +124,7 @@
return -1;
}
+ timer->kernel_timer_id = -1;
timer->sigev_notify = (evp == nullptr) ? SIGEV_SIGNAL : evp->sigev_notify;
// If not a SIGEV_THREAD timer, the kernel can handle it without our help.
@@ -149,6 +165,10 @@
sigaddset64(&sigset, TIMER_SIGNAL);
sigset64_t old_sigset;
+ // Prevent the child thread from running until the timer has been created.
+ timer->startup_handshake_lock.init(false);
+ timer->startup_handshake_lock.lock();
+
// Use __rt_sigprocmask instead of sigprocmask64 to avoid filtering out TIMER_SIGNAL.
__rt_sigprocmask(SIG_BLOCK, &sigset, &old_sigset, sizeof(sigset));
@@ -162,21 +182,21 @@
return -1;
}
+ // Try to create the kernel timer.
sigevent se = *evp;
se.sigev_signo = TIMER_SIGNAL;
se.sigev_notify = SIGEV_THREAD_ID;
se.sigev_notify_thread_id = pthread_gettid_np(timer->callback_thread);
- if (__timer_create(clock_id, &se, &timer->kernel_timer_id) == -1) {
- __timer_thread_stop(timer);
+ rc = __timer_create(clock_id, &se, &timer->kernel_timer_id);
+
+ // Let the child run (whether we created the kernel timer or not).
+ timer->startup_handshake_lock.unlock();
+ // If __timer_create(2) failed, the child will kill itself and free the
+ // timer struct, so we just need to exit.
+ if (rc == -1) {
return -1;
}
- // Give the thread a specific meaningful name.
- // It can't do this itself because the kernel timer isn't created until after it's running.
- char name[16]; // 16 is the kernel-imposed limit.
- snprintf(name, sizeof(name), "POSIX timer %d", to_kernel_timer_id(timer));
- pthread_setname_np(timer->callback_thread, name);
-
*timer_id = timer;
return 0;
}
diff --git a/libc/bionic/sys_thread_properties.cpp b/libc/bionic/sys_thread_properties.cpp
index d1a73b7..d7188f5 100644
--- a/libc/bionic/sys_thread_properties.cpp
+++ b/libc/bionic/sys_thread_properties.cpp
@@ -77,35 +77,9 @@
// Find the thread-pointer register for the given thread.
void** tp_reg = nullptr;
-#if defined(__x86_64__)
- {
- ErrnoRestorer errno_restorer;
- errno = 0;
- uintptr_t fs_base = ptrace(PTRACE_PEEKUSER, tid, offsetof(user_regs_struct, fs_base), nullptr);
- if (errno == 0) {
- tp_reg = reinterpret_cast<void**>(fs_base);
- }
- }
-#elif defined(__i386__)
- struct user_regs_struct regs;
- struct iovec pt_iov = {
- .iov_base = ®s,
- .iov_len = sizeof(regs),
- };
-
- if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) == 0) {
- struct user_desc u_info;
- u_info.entry_number = regs.xgs >> 3;
- if (ptrace(PTRACE_GET_THREAD_AREA, tid, u_info.entry_number, &u_info) == 0) {
- tp_reg = reinterpret_cast<void**>(u_info.base_addr);
- }
- }
-#elif defined(__aarch64__)
+#if defined(__aarch64__)
uint64_t reg;
- struct iovec pt_iov {
- .iov_base = ®, .iov_len = sizeof(reg),
- };
-
+ struct iovec pt_iov { .iov_base = ®, .iov_len = sizeof(reg) };
if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TLS, &pt_iov) == 0) {
tp_reg = reinterpret_cast<void**>(reg);
}
@@ -114,6 +88,31 @@
// Reset the tp_reg if ptrace was unsuccessful.
tp_reg = nullptr;
}
+#elif defined(__i386__)
+ struct user_regs_struct regs;
+ struct iovec pt_iov = { .iov_base = ®s, .iov_len = sizeof(regs) };
+ if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) == 0) {
+ struct user_desc u_info;
+ u_info.entry_number = regs.xgs >> 3;
+ if (ptrace(PTRACE_GET_THREAD_AREA, tid, u_info.entry_number, &u_info) == 0) {
+ tp_reg = reinterpret_cast<void**>(u_info.base_addr);
+ }
+ }
+#elif defined(__riscv)
+ struct user_regs_struct regs;
+ struct iovec pt_iov = { .iov_base = ®s, .iov_len = sizeof(regs) };
+ if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) == 0) {
+ tp_reg = reinterpret_cast<void**>(regs.tp);
+ }
+#elif defined(__x86_64__)
+ {
+ ErrnoRestorer errno_restorer;
+ errno = 0;
+ uintptr_t fs_base = ptrace(PTRACE_PEEKUSER, tid, offsetof(user_regs_struct, fs_base), nullptr);
+ if (errno == 0) {
+ tp_reg = reinterpret_cast<void**>(fs_base);
+ }
+ }
#endif
if (tp_reg == nullptr) {
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index d6416e5..38de84b 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -1166,23 +1166,19 @@
}
}
-static inline void
-entry_mru_remove( Entry* e )
-{
- e->mru_prev->mru_next = e->mru_next;
- e->mru_next->mru_prev = e->mru_prev;
+static __inline__ void entry_mru_remove(Entry* e) {
+ e->mru_prev->mru_next = e->mru_next;
+ e->mru_next->mru_prev = e->mru_prev;
}
-static inline void
-entry_mru_add( Entry* e, Entry* list )
-{
- Entry* first = list->mru_next;
+static __inline__ void entry_mru_add(Entry* e, Entry* list) {
+ Entry* first = list->mru_next;
- e->mru_next = first;
- e->mru_prev = list;
+ e->mru_next = first;
+ e->mru_prev = list;
- list->mru_next = e;
- first->mru_prev = e;
+ list->mru_next = e;
+ first->mru_prev = e;
}
/* compute the hash of a given entry, this is a hash of most
diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h
index 113897c..1bde3a5 100644
--- a/libc/include/android/api-level.h
+++ b/libc/include/android/api-level.h
@@ -168,7 +168,10 @@
*/
#define __ANDROID_API_U__ 34
-/** Names the "V" API level (35), for comparison against `__ANDROID_API__`. */
+/**
+ * Names the Android 15 (aka "V" or "VanillaIceCream") API level (35),
+ * for comparison against `__ANDROID_API__`.
+ */
#define __ANDROID_API_V__ 35
/* This file is included in <features.h>, and might be used from .S files. */
@@ -191,7 +194,7 @@
#if __ANDROID_API__ < 29
/* android_get_device_api_level is a static inline before API level 29. */
-#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static inline
+#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE static __inline
#include <bits/get_device_api_level_inlines.h>
#undef __BIONIC_GET_DEVICE_API_LEVEL_INLINE
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index a5061c7..b42e5b2 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef __ANDROID_DLEXT_H__
-#define __ANDROID_DLEXT_H__
+#pragma once
#include <stdbool.h>
#include <stddef.h>
@@ -101,7 +100,7 @@
ANDROID_DLEXT_FORCE_LOAD = 0x40,
// Historically we had two other options for ART.
- // They were last available in Android P.
+ // They were last available in API level 28.
// Reuse these bits last!
// ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80
// ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS = 0x100
@@ -115,7 +114,7 @@
ANDROID_DLEXT_USE_NAMESPACE = 0x200,
/**
- * Instructs dlopen to apply `ANDROID_DLEXT_RESERVED_ADDRESS`,
+ * Instructs dlopen() to apply `ANDROID_DLEXT_RESERVED_ADDRESS`,
* `ANDROID_DLEXT_RESERVED_ADDRESS_HINT`, `ANDROID_DLEXT_WRITE_RELRO` and
* `ANDROID_DLEXT_USE_RELRO` to any libraries loaded as dependencies of the
* main library as well.
@@ -151,7 +150,7 @@
struct android_namespace_t;
-/** Used to pass Android-specific arguments to `android_dlopen_ext`. */
+/** Used to pass Android-specific arguments to android_dlopen_ext(). */
typedef struct {
/** A bitmask of `ANDROID_DLEXT_` enum values. */
uint64_t flags;
@@ -183,5 +182,3 @@
__END_DECLS
/** @} */
-
-#endif
diff --git a/libc/include/android/legacy_stdlib_inlines.h b/libc/include/android/legacy_stdlib_inlines.h
index 0ca1022..f0985fe 100644
--- a/libc/include/android/legacy_stdlib_inlines.h
+++ b/libc/include/android/legacy_stdlib_inlines.h
@@ -38,15 +38,15 @@
__BEGIN_DECLS
-static inline double strtod_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, locale_t _Nonnull __l) {
+static __inline double strtod_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, locale_t _Nonnull __l) {
return strtod(__s, __end_ptr);
}
-static inline float strtof_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, locale_t _Nonnull __l) {
+static __inline float strtof_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, locale_t _Nonnull __l) {
return strtof(__s, __end_ptr);
}
-static inline long strtol_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, int __base, locale_t _Nonnull __l) {
+static __inline long strtol_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, int __base, locale_t _Nonnull __l) {
return strtol(__s, __end_ptr, __base);
}
diff --git a/libc/include/android/legacy_termios_inlines.h b/libc/include/android/legacy_termios_inlines.h
index e557525..a816b40 100644
--- a/libc/include/android/legacy_termios_inlines.h
+++ b/libc/include/android/legacy_termios_inlines.h
@@ -39,14 +39,14 @@
#include <sys/ioctl.h>
#include <sys/types.h>
-#define __BIONIC_TERMIOS_INLINE static inline
+#define __BIONIC_TERMIOS_INLINE static __inline
#include <bits/termios_inlines.h>
#endif
#if __ANDROID_API__ < 35
-#define __BIONIC_TERMIOS_WINSIZE_INLINE static inline
+#define __BIONIC_TERMIOS_WINSIZE_INLINE static __inline
#include <bits/termios_winsize_inlines.h>
#endif
diff --git a/libc/include/android/legacy_threads_inlines.h b/libc/include/android/legacy_threads_inlines.h
index 06e7438..c614cd0 100644
--- a/libc/include/android/legacy_threads_inlines.h
+++ b/libc/include/android/legacy_threads_inlines.h
@@ -32,7 +32,7 @@
#if __ANDROID_API__ < 30
-#define __BIONIC_THREADS_INLINE static inline
+#define __BIONIC_THREADS_INLINE static __inline
#include <bits/threads_inlines.h>
#endif
diff --git a/libc/include/android/legacy_unistd_inlines.h b/libc/include/android/legacy_unistd_inlines.h
index ac9f3b3..4a5206b 100644
--- a/libc/include/android/legacy_unistd_inlines.h
+++ b/libc/include/android/legacy_unistd_inlines.h
@@ -32,7 +32,7 @@
#if __ANDROID_API__ < 28
-#define __BIONIC_SWAB_INLINE static inline
+#define __BIONIC_SWAB_INLINE static __inline
#include <bits/swab.h>
#endif
diff --git a/libc/include/bits/stdatomic.h b/libc/include/bits/stdatomic.h
index 8df86e2..c74eafd 100644
--- a/libc/include/bits/stdatomic.h
+++ b/libc/include/bits/stdatomic.h
@@ -138,11 +138,11 @@
* 7.17.4 Fences.
*/
-static inline void atomic_thread_fence(memory_order __order __attribute__((__unused__))) {
+static __inline void atomic_thread_fence(memory_order __order __attribute__((__unused__))) {
__c11_atomic_thread_fence(__order);
}
-static inline void atomic_signal_fence(memory_order __order __attribute__((__unused__))) {
+static __inline void atomic_signal_fence(memory_order __order __attribute__((__unused__))) {
__c11_atomic_signal_fence(__order);
}
@@ -269,18 +269,18 @@
#define ATOMIC_FLAG_INIT { ATOMIC_VAR_INIT(false) }
-static inline bool atomic_flag_test_and_set_explicit(volatile atomic_flag * _Nonnull __object, memory_order __order) {
+static __inline bool atomic_flag_test_and_set_explicit(volatile atomic_flag * _Nonnull __object, memory_order __order) {
return (atomic_exchange_explicit(&__object->__flag, 1, __order));
}
-static inline void atomic_flag_clear_explicit(volatile atomic_flag * _Nonnull __object, memory_order __order) {
+static __inline void atomic_flag_clear_explicit(volatile atomic_flag * _Nonnull __object, memory_order __order) {
atomic_store_explicit(&__object->__flag, 0, __order);
}
-static inline bool atomic_flag_test_and_set(volatile atomic_flag * _Nonnull __object) {
+static __inline bool atomic_flag_test_and_set(volatile atomic_flag * _Nonnull __object) {
return (atomic_flag_test_and_set_explicit(__object, memory_order_seq_cst));
}
-static inline void atomic_flag_clear(volatile atomic_flag * _Nonnull __object) {
+static __inline void atomic_flag_clear(volatile atomic_flag * _Nonnull __object) {
atomic_flag_clear_explicit(__object, memory_order_seq_cst);
}
diff --git a/libc/include/bits/swab.h b/libc/include/bits/swab.h
index ebb7c74..9591c2e 100644
--- a/libc/include/bits/swab.h
+++ b/libc/include/bits/swab.h
@@ -33,7 +33,7 @@
#include <sys/types.h>
#if !defined(__BIONIC_SWAB_INLINE)
-#define __BIONIC_SWAB_INLINE static inline
+#define __BIONIC_SWAB_INLINE static __inline
#endif
__BEGIN_DECLS
diff --git a/libc/include/bits/termios_inlines.h b/libc/include/bits/termios_inlines.h
index 702f433..a884b59 100644
--- a/libc/include/bits/termios_inlines.h
+++ b/libc/include/bits/termios_inlines.h
@@ -37,7 +37,7 @@
#include <linux/termios.h>
#if !defined(__BIONIC_TERMIOS_INLINE)
-#define __BIONIC_TERMIOS_INLINE static inline
+#define __BIONIC_TERMIOS_INLINE static __inline
#endif
__BEGIN_DECLS
@@ -45,7 +45,7 @@
// Supporting separate input and output speeds would require an ABI
// change for `struct termios`.
-static inline speed_t cfgetspeed(const struct termios* _Nonnull s) {
+static __inline speed_t cfgetspeed(const struct termios* _Nonnull s) {
return __BIONIC_CAST(static_cast, speed_t, s->c_cflag & CBAUD);
}
diff --git a/libc/include/bits/termios_winsize_inlines.h b/libc/include/bits/termios_winsize_inlines.h
index 0d188e7..ae246e4 100644
--- a/libc/include/bits/termios_winsize_inlines.h
+++ b/libc/include/bits/termios_winsize_inlines.h
@@ -36,7 +36,7 @@
#include <linux/termios.h>
#if !defined(__BIONIC_TERMIOS_WINSIZE_INLINE)
-#define __BIONIC_TERMIOS_WINSIZE_INLINE static inline
+#define __BIONIC_TERMIOS_WINSIZE_INLINE static __inline
#endif
__BEGIN_DECLS
diff --git a/libc/include/bits/threads_inlines.h b/libc/include/bits/threads_inlines.h
index 074e1ca..459866e 100644
--- a/libc/include/bits/threads_inlines.h
+++ b/libc/include/bits/threads_inlines.h
@@ -38,7 +38,7 @@
__BEGIN_DECLS
-static inline int __bionic_thrd_error(int __pthread_code) {
+static __inline int __bionic_thrd_error(int __pthread_code) {
switch (__pthread_code) {
case 0: return 0;
case ENOMEM: return thrd_nomem;
@@ -124,7 +124,7 @@
};
#pragma clang diagnostic pop
-static inline void* _Nonnull __bionic_thrd_trampoline(void* _Nonnull __arg) {
+static __inline void* _Nonnull __bionic_thrd_trampoline(void* _Nonnull __arg) {
struct __bionic_thrd_data __data =
*__BIONIC_CAST(static_cast, struct __bionic_thrd_data*, __arg);
free(__arg);
diff --git a/libc/include/ctype.h b/libc/include/ctype.h
index 5cad412..c15ee56 100644
--- a/libc/include/ctype.h
+++ b/libc/include/ctype.h
@@ -42,7 +42,7 @@
* also provide actual symbols for any caller that needs them.
*/
#if !defined(__BIONIC_CTYPE_INLINE)
-#define __BIONIC_CTYPE_INLINE static inline
+#define __BIONIC_CTYPE_INLINE static __inline
#endif
/** Internal implementation detail. Do not use. */
diff --git a/libc/include/link.h b/libc/include/link.h
index 33fea49..ee1fc42 100644
--- a/libc/include/link.h
+++ b/libc/include/link.h
@@ -25,8 +25,13 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#ifndef _LINK_H_
-#define _LINK_H_
+
+#pragma once
+
+/**
+ * @file link.h
+ * @brief Extra dynamic linker functionality (see also <dlfcn.h>).
+ */
#include <stdint.h>
#include <sys/cdefs.h>
@@ -37,32 +42,80 @@
__BEGIN_DECLS
#if defined(__LP64__)
+/** Convenience macro to get the appropriate 32-bit or 64-bit <elf.h> type for the caller's bitness. */
#define ElfW(type) Elf64_ ## type
#else
+/** Convenience macro to get the appropriate 32-bit or 64-bit <elf.h> type for the caller's bitness. */
#define ElfW(type) Elf32_ ## type
#endif
+/**
+ * Information passed by dl_iterate_phdr() to the callback.
+ */
struct dl_phdr_info {
+ /** The address of the shared object. */
ElfW(Addr) dlpi_addr;
+ /** The name of the shared object. */
const char* _Nullable dlpi_name;
+ /** Pointer to the shared object's program headers. */
const ElfW(Phdr)* _Nullable dlpi_phdr;
+ /** Number of program headers pointed to by `dlpi_phdr`. */
ElfW(Half) dlpi_phnum;
- // These fields were added in Android R.
+ /**
+ * The total number of library load events at the time dl_iterate_phdr() was
+ * called.
+ *
+ * This field is only available since API level 30; you can use the size
+ * passed to the callback to determine whether you have the full struct,
+ * or just the fields up to and including `dlpi_phnum`.
+ */
unsigned long long dlpi_adds;
+ /**
+ * The total number of library unload events at the time dl_iterate_phdr() was
+ * called.
+ *
+ * This field is only available since API level 30; you can use the size
+ * passed to the callback to determine whether you have the full struct,
+ * or just the fields up to and including `dlpi_phnum`.
+ */
unsigned long long dlpi_subs;
+ /**
+ * The module ID for TLS relocations in this shared object.
+ *
+ * This field is only available since API level 30; you can use the size
+ * passed to the callback to determine whether you have the full struct,
+ * or just the fields up to and including `dlpi_phnum`.
+ */
size_t dlpi_tls_modid;
+ /**
+ * The caller's TLS data for this shared object.
+ *
+ * This field is only available since API level 30; you can use the size
+ * passed to the callback to determine whether you have the full struct,
+ * or just the fields up to and including `dlpi_phnum`.
+ */
void* _Nullable dlpi_tls_data;
};
-int dl_iterate_phdr(int (* _Nonnull __callback)(struct dl_phdr_info* _Nonnull, size_t, void* _Nullable), void* _Nullable __data);
+/**
+ * [dl_iterate_phdr(3)](http://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html)
+ * calls the given callback once for every loaded shared object. The size
+ * argument to the callback lets you determine whether you have a smaller
+ * `dl_phdr_info` from before API level 30, or the newer full one.
+ * The data argument to the callback is whatever you pass as the data argument
+ * to dl_iterate_phdr().
+ *
+ * Returns the value returned by the final call to the callback.
+ */
+int dl_iterate_phdr(int (* _Nonnull __callback)(struct dl_phdr_info* _Nonnull __info, size_t __size, void* _Nullable __data), void* _Nullable __data);
#ifdef __arm__
typedef uintptr_t _Unwind_Ptr;
_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr, int* _Nonnull);
#endif
-/* Used by the dynamic linker to communicate with the debugger. */
+/** Used by the dynamic linker to communicate with the debugger. */
struct link_map {
ElfW(Addr) l_addr;
char* _Nullable l_name;
@@ -71,7 +124,7 @@
struct link_map* _Nullable l_prev;
};
-/* Used by the dynamic linker to communicate with the debugger. */
+/** Used by the dynamic linker to communicate with the debugger. */
struct r_debug {
int32_t r_version;
struct link_map* _Nullable r_map;
@@ -85,5 +138,3 @@
};
__END_DECLS
-
-#endif
diff --git a/libc/include/strings.h b/libc/include/strings.h
index 6ec3bdf..4b8cc08 100644
--- a/libc/include/strings.h
+++ b/libc/include/strings.h
@@ -50,7 +50,7 @@
#include <bits/strcasecmp.h>
#if !defined(__BIONIC_STRINGS_INLINE)
-#define __BIONIC_STRINGS_INLINE static inline
+#define __BIONIC_STRINGS_INLINE static __inline
#endif
#undef ffs
@@ -61,13 +61,13 @@
/** Deprecated. Use memmove() instead. */
#define bcopy(b1, b2, len) __bionic_bcopy((b1), (b2), (len))
-static inline __always_inline void __bionic_bcopy(const void* _Nonnull b1, void* _Nonnull b2, size_t len) {
+static __inline __always_inline void __bionic_bcopy(const void* _Nonnull b1, void* _Nonnull b2, size_t len) {
__builtin_memmove(b2, b1, len);
}
/** Deprecated. Use memset() instead. */
#define bzero(b, len) __bionic_bzero((b), (len))
-static inline __always_inline void __bionic_bzero(void* _Nonnull b, size_t len) {
+static __inline __always_inline void __bionic_bzero(void* _Nonnull b, size_t len) {
__builtin_memset(b, 0, len);
}
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 3218d15..5d1718e 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -87,9 +87,12 @@
#define __STRING(x) #x
#define ___STRING(x) __STRING(x)
-#if defined(__cplusplus)
-#define __inline inline /* convert to C++ keyword */
-#endif /* !__cplusplus */
+// C++ has `inline` as a keyword, as does C99, but ANSI C (aka C89 aka C90)
+// does not. Everything accepts the `__inline__` extension though. We could
+// just use that directly in our own code, but there's historical precedent
+// for `__inline` meaning it's still used in upstream BSD code (and potentially
+// downstream in vendor or app code).
+#define __inline __inline__
#define __always_inline __attribute__((__always_inline__))
#define __attribute_const__ __attribute__((__const__))
@@ -260,7 +263,7 @@
* them available externally. FORTIFY'ed functions try to be as close to possible as 'invisible';
* having stack protectors detracts from that (b/182948263).
*/
-# define __BIONIC_FORTIFY_INLINE static inline __attribute__((__no_stack_protector__)) \
+# define __BIONIC_FORTIFY_INLINE static __inline __attribute__((__no_stack_protector__)) \
__always_inline __VERSIONER_FORTIFY_INLINE
/*
* We should use __BIONIC_FORTIFY_VARIADIC instead of __BIONIC_FORTIFY_INLINE
@@ -268,9 +271,9 @@
* The __always_inline attribute is useless, misleading, and could trigger
* clang compiler bug to incorrectly inline variadic functions.
*/
-# define __BIONIC_FORTIFY_VARIADIC static inline
+# define __BIONIC_FORTIFY_VARIADIC static __inline
/* Error functions don't have bodies, so they can just be static. */
-# define __BIONIC_ERROR_FUNCTION_VISIBILITY static __attribute__((__unused__))
+# define __BIONIC_ERROR_FUNCTION_VISIBILITY static __unused
#else
/* Further increase sharing for some inline functions */
# define __pass_object_size_n(n)
diff --git a/libc/include/sys/system_properties.h b/libc/include/sys/system_properties.h
index dc869da..ae94db5 100644
--- a/libc/include/sys/system_properties.h
+++ b/libc/include/sys/system_properties.h
@@ -26,8 +26,12 @@
* SUCH DAMAGE.
*/
-#ifndef _INCLUDE_SYS_SYSTEM_PROPERTIES_H
-#define _INCLUDE_SYS_SYSTEM_PROPERTIES_H
+#pragma once
+
+/**
+ * @file system_properties.h
+ * @brief System properties.
+ */
#include <sys/cdefs.h>
#include <stdbool.h>
@@ -36,39 +40,53 @@
__BEGIN_DECLS
+/** An opaque structure representing a system property. */
typedef struct prop_info prop_info;
+/**
+ * The limit on the length of a property value.
+ * (See PROP_NAME_MAX for property names.)
+ */
#define PROP_VALUE_MAX 92
-/*
+/**
* Sets system property `name` to `value`, creating the system property if it doesn't already exist.
+ *
+ * Returns 0 on success, or -1 on failure.
*/
int __system_property_set(const char* _Nonnull __name, const char* _Nonnull __value);
-/*
+/**
* Returns a `prop_info` corresponding system property `name`, or nullptr if it doesn't exist.
- * Use __system_property_read_callback to query the current value.
+ * Use __system_property_read_callback() to query the current value.
*
- * Property lookup is expensive, so it can be useful to cache the result of this function.
+ * Property lookup is expensive, so it can be useful to cache the result of this
+ * function rather than using __system_property_get().
*/
const prop_info* _Nullable __system_property_find(const char* _Nonnull __name);
-/*
- * Calls `callback` with a consistent trio of name, value, and serial number for property `pi`.
+/**
+ * Calls `callback` with a consistent trio of name, value, and serial number
+ * for property `pi`.
+ *
+ * Available since API level 26.
*/
void __system_property_read_callback(const prop_info* _Nonnull __pi,
void (* _Nonnull __callback)(void* _Nullable __cookie, const char* _Nonnull __name, const char* _Nonnull __value, uint32_t __serial),
void* _Nullable __cookie) __INTRODUCED_IN(26);
-/*
+/**
* Passes a `prop_info` for each system property to the provided
- * callback. Use __system_property_read_callback() to read the value.
+ * callback. Use __system_property_read_callback() to read the value of
+ * any of the properties.
*
* This method is for inspecting and debugging the property system, and not generally useful.
+ *
+ * Returns 0 on success, or -1 on failure.
*/
int __system_property_foreach(void (* _Nonnull __callback)(const prop_info* _Nonnull __pi, void* _Nullable __cookie), void* _Nullable __cookie);
-/*
+/**
* Waits for the specific system property identified by `pi` to be updated
* past `old_serial`. Waits no longer than `relative_timeout`, or forever
* if `relative_timeout` is null.
@@ -79,20 +97,24 @@
*
* Returns true and updates `*new_serial_ptr` on success, or false if the call
* timed out.
+ *
+ * Available since API level 26.
*/
struct timespec;
bool __system_property_wait(const prop_info* _Nullable __pi, uint32_t __old_serial, uint32_t* _Nonnull __new_serial_ptr, const struct timespec* _Nullable __relative_timeout)
__INTRODUCED_IN(26);
-/* Deprecated. In Android O and above, there's no limit on property name length. */
+/**
+ * Deprecated: there's no limit on the length of a property name since
+ * API level 26, though the limit on property values (PROP_VALUE_MAX) remains.
+ */
#define PROP_NAME_MAX 32
-/* Deprecated. Use __system_property_read_callback instead. */
+
+/** Deprecated. Use __system_property_read_callback() instead. */
int __system_property_read(const prop_info* _Nonnull __pi, char* _Nullable __name, char* _Nonnull __value);
-/* Deprecated. Use __system_property_read_callback instead. */
+/** Deprecated. Use __system_property_read_callback() instead. */
int __system_property_get(const char* _Nonnull __name, char* _Nonnull __value);
-/* Deprecated. Use __system_property_foreach instead. */
+/** Deprecated. Use __system_property_foreach() instead. */
const prop_info* _Nullable __system_property_find_nth(unsigned __n);
__END_DECLS
-
-#endif
diff --git a/libc/kernel/tools/cpp.py b/libc/kernel/tools/cpp.py
index 0fd6e46..08b786a 100755
--- a/libc/kernel/tools/cpp.py
+++ b/libc/kernel/tools/cpp.py
@@ -2345,11 +2345,11 @@
def test_function_keep_attribute_structs(self):
text = """\
-static inline struct some_struct1 * function(struct some_struct2 * e) {
+static __inline__ struct some_struct1 * function(struct some_struct2 * e) {
}
"""
expected = """\
-static inline struct some_struct1 * function(struct some_struct2 * e) {
+static __inline__ struct some_struct1 * function(struct some_struct2 * e) {
}
"""
self.assertEqual(self.parse(text, set(["function"])), expected)
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/linker/linker_main.cpp b/linker/linker_main.cpp
index 089eceb..e27fd91 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -422,20 +422,11 @@
ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
- // We haven't supported non-PIE since Lollipop for security reasons.
+ // For security reasons we dropped non-PIE support in API level 21,
+ // and the NDK no longer supports earlier API levels.
if (elf_hdr->e_type != ET_DYN) {
- // We don't use async_safe_fatal here because we don't want a tombstone:
- // even after several years we still find ourselves on app compatibility
- // investigations because some app's trying to launch an executable that
- // hasn't worked in at least three years, and we've "helpfully" dropped a
- // tombstone for them. The tombstone never provided any detail relevant to
- // fixing the problem anyway, and the utility of drawing extra attention
- // to the problem is non-existent at this late date.
- async_safe_format_fd(STDERR_FILENO,
- "\"%s\": error: Android 5.0 and later only support "
- "position-independent executables (-fPIE).\n",
- g_argv[0]);
- _exit(EXIT_FAILURE);
+ __linker_error("error: %s: Android only supports position-independent "
+ "executables (-fPIE)\n", exe_info.path.c_str());
}
// Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index fa712a1..b9229ca 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -298,7 +298,6 @@
}
if (header_.e_shentsize != sizeof(ElfW(Shdr))) {
- // Fail if app is targeting Android O or above
if (get_application_target_sdk_version() >= 26) {
DL_ERR_AND_LOG("\"%s\" has unsupported e_shentsize: 0x%x (expected 0x%zx)",
name_.c_str(), header_.e_shentsize, sizeof(ElfW(Shdr)));
@@ -312,12 +311,10 @@
}
if (header_.e_shstrndx == 0) {
- // Fail if app is targeting Android O or above
if (get_application_target_sdk_version() >= 26) {
DL_ERR_AND_LOG("\"%s\" has invalid e_shstrndx", name_.c_str());
return false;
}
-
DL_WARN_documented_change(26,
"invalid-elf-header_section-headers-enforced-for-api-level-26",
"\"%s\" has invalid e_shstrndx", name_.c_str());
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index 6ae8bfd..0de0a01 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -174,31 +174,23 @@
}
}
-#if defined(__aarch64__)
+#if defined(__arm__)
+#define SET_FREG(n, v) asm volatile("vmov.f64 d"#n ", #"#v : : : "d"#n)
+#define GET_FREG(n) ({ double _r; asm volatile("fcpyd %P0, d"#n : "=w"(_r) : :); _r;})
+#define CLEAR_FREG(n) asm volatile("vmov.i64 d"#n ", #0x0" : : : "d"#n)
+#elif defined(__aarch64__)
#define SET_FREG(n, v) asm volatile("fmov d"#n ", "#v : : : "d"#n)
+#define GET_FREG(n) ({ double _r; asm volatile("fmov %0, d"#n : "=r"(_r) : :); _r; })
#define CLEAR_FREG(n) asm volatile("fmov d"#n ", xzr" : : : "d"#n)
+#endif
+
+#if defined(__arm__) || defined(__aarch64__)
#define SET_FREGS \
SET_FREG(8, 8.0); SET_FREG(9, 9.0); SET_FREG(10, 10.0); SET_FREG(11, 11.0); \
SET_FREG(12, 12.0); SET_FREG(13, 13.0); SET_FREG(14, 14.0); SET_FREG(15, 15.0);
#define CLEAR_FREGS \
CLEAR_FREG(8); CLEAR_FREG(9); CLEAR_FREG(10); CLEAR_FREG(11); \
CLEAR_FREG(12); CLEAR_FREG(13); CLEAR_FREG(14); CLEAR_FREG(15);
-#define GET_FREG(n) ({ double _r; asm volatile("fmov %0, d"#n : "=r"(_r) : :); _r; })
-#define CHECK_FREGS \
- EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \
- EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \
- EXPECT_EQ(12.0, GET_FREG(12)); EXPECT_EQ(13.0, GET_FREG(13)); \
- EXPECT_EQ(14.0, GET_FREG(14)); EXPECT_EQ(15.0, GET_FREG(15));
-#elif defined(__arm__)
-#define SET_FREG(n, v) \
- ({ const double _v{v}; asm volatile("fcpyd d"#n ", %P0" : : "w"(_v) : "d"#n); })
-#define SET_FREGS \
- SET_FREG(8, 8); SET_FREG(9, 9); SET_FREG(10, 10); SET_FREG(11, 11); \
- SET_FREG(12, 12); SET_FREG(13, 13); SET_FREG(14, 14); SET_FREG(15, 15);
-#define CLEAR_FREGS \
- SET_FREG(8, 0); SET_FREG(9, 0); SET_FREG(10, 0); SET_FREG(11, 0); \
- SET_FREG(12, 0); SET_FREG(13, 0); SET_FREG(14, 0); SET_FREG(15, 0);
-#define GET_FREG(n) ({ double _r; asm volatile("fcpyd %P0, d"#n : "=w"(_r) : :); _r;})
#define CHECK_FREGS \
EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \
EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \
diff --git a/tests/stack_protector_test.cpp b/tests/stack_protector_test.cpp
index c4be78c..aea791c 100644
--- a/tests/stack_protector_test.cpp
+++ b/tests/stack_protector_test.cpp
@@ -136,7 +136,7 @@
if (stack_mte_enabled()) {
GTEST_SKIP() << "Stack MTE is enabled, stack protector is not available";
} else if (hwasan_enabled()) {
- ASSERT_EXIT(modify_stack_protector_test(), testing::KilledBySignal(SIGABRT), "tag-mismatch");
+ GTEST_SKIP() << "HWASan is enabled, stack protector is not testable";
} else {
ASSERT_EXIT(modify_stack_protector_test(), testing::KilledBySignal(SIGABRT),
"stack corruption detected");
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index ca8e260..baafbf6 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -31,6 +31,8 @@
#include <thread>
#include "SignalUtils.h"
+#include "android-base/file.h"
+#include "android-base/strings.h"
#include "utils.h"
using namespace std::chrono_literals;
@@ -797,21 +799,41 @@
ASSERT_EQ(1, timer_create_NULL_signal_handler_invocation_count);
}
-TEST(time, timer_create_EINVAL) {
- clockid_t invalid_clock = 16;
+static int GetThreadCount() {
+ std::string status;
+ if (android::base::ReadFileToString("/proc/self/status", &status)) {
+ for (const auto& line : android::base::Split(status, "\n")) {
+ int thread_count;
+ if (sscanf(line.c_str(), "Threads: %d", &thread_count) == 1) {
+ return thread_count;
+ }
+ }
+ }
+ return -1;
+}
- // A SIGEV_SIGNAL timer is easy; the kernel does all that.
+TEST(time, timer_create_EINVAL) {
+ const clockid_t kInvalidClock = 16;
+
+ // A SIGEV_SIGNAL timer failure is easy; that's the kernel's problem.
timer_t timer_id;
- ASSERT_EQ(-1, timer_create(invalid_clock, nullptr, &timer_id));
+ ASSERT_EQ(-1, timer_create(kInvalidClock, nullptr, &timer_id));
ASSERT_ERRNO(EINVAL);
- // A SIGEV_THREAD timer is more interesting because we have stuff to clean up.
- sigevent se;
- memset(&se, 0, sizeof(se));
+ // A SIGEV_THREAD timer failure is more interesting because we have a thread
+ // to clean up (https://issuetracker.google.com/340125671).
+ sigevent se = {};
se.sigev_notify = SIGEV_THREAD;
se.sigev_notify_function = NoOpNotifyFunction;
- ASSERT_EQ(-1, timer_create(invalid_clock, &se, &timer_id));
+ ASSERT_EQ(-1, timer_create(kInvalidClock, &se, &timer_id));
ASSERT_ERRNO(EINVAL);
+
+ // timer_create() doesn't guarantee that the thread will be dead _before_
+ // it returns because that would require extra synchronization that's
+ // unnecessary in the normal (successful) case. A timeout here means we
+ // leaked a thread.
+ while (GetThreadCount() > 1) {
+ }
}
TEST(time, timer_create_multiple) {
diff --git a/tests/utils.h b/tests/utils.h
index dcb08f5..3c83b73 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -38,6 +38,7 @@
#endif
#include <atomic>
+#include <iomanip>
#include <string>
#include <regex>
@@ -253,7 +254,7 @@
AssertChildExited(pid, expected_exit_status, &error_msg);
if (expected_output_regex != nullptr) {
if (!std::regex_search(output_, std::regex(expected_output_regex))) {
- FAIL() << "regex " << expected_output_regex << " didn't match " << output_;
+ FAIL() << "regex " << std::quoted(expected_output_regex) << " didn't match " << std::quoted(output_);
}
}
}