Merge "Use the ion.h from the kernel headers."
diff --git a/docs/status.md b/docs/status.md
index 2666e58..a0e6824 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -53,8 +53,11 @@
* <spawn.h>
* `swab`
* `syncfs`
+
+New libc behavior in P:
* `%C` and `%S` support in the printf family (previously only the wprintf family supported these)
* `%mc`/`%ms`/`%m[` support in the scanf family
+ * `%s` support in strptime (strftime already supported it)
New libc functions in O:
* `sendto` FORTIFY support
diff --git a/libc/Android.bp b/libc/Android.bp
index 579c63c..360aea3 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -285,7 +285,6 @@
cflags: [
"-Wno-sign-compare",
- "-Wno-uninitialized",
"-Wno-unused-parameter",
"-include freebsd-compat.h",
],
@@ -368,7 +367,6 @@
},
cflags: [
"-Wno-sign-compare",
- "-Wno-uninitialized",
"-Wno-unused-parameter",
"-DPOSIX_MISTAKE",
"-include netbsd-compat.h",
@@ -481,7 +479,6 @@
"upstream-openbsd/lib/libc/stdlib/reallocarray.c",
"upstream-openbsd/lib/libc/stdlib/remque.c",
"upstream-openbsd/lib/libc/stdlib/setenv.c",
- "upstream-openbsd/lib/libc/stdlib/system.c",
"upstream-openbsd/lib/libc/stdlib/tfind.c",
"upstream-openbsd/lib/libc/stdlib/tsearch.c",
"upstream-openbsd/lib/libc/string/strcasecmp.c",
@@ -499,7 +496,6 @@
cflags: [
"-Wno-sign-compare",
- "-Wno-uninitialized",
"-Wno-unused-parameter",
"-include openbsd-compat.h",
],
@@ -639,7 +635,6 @@
cflags: [
"-Wno-sign-compare",
- "-Wno-uninitialized",
"-Wno-unused-parameter",
"-include openbsd-compat.h",
],
@@ -689,7 +684,6 @@
cflags: [
"-Wno-sign-compare",
- "-Wno-uninitialized",
"-include openbsd-compat.h",
],
@@ -1342,6 +1336,7 @@
"bionic/setpgrp.cpp",
"bionic/sigaction.cpp",
"bionic/signal.cpp",
+ "bionic/sigprocmask.cpp",
"bionic/socket.cpp",
"bionic/spawn.cpp",
"bionic/stat.cpp",
@@ -1368,6 +1363,7 @@
"bionic/sys_time.cpp",
"bionic/sysinfo.cpp",
"bionic/syslog.cpp",
+ "bionic/system.cpp",
"bionic/system_property_api.cpp",
"bionic/system_property_set.cpp",
"bionic/tdestroy.cpp",
diff --git a/libc/bionic/__libc_current_sigrtmin.cpp b/libc/bionic/__libc_current_sigrtmin.cpp
index 04caa89..d2ea75d 100644
--- a/libc/bionic/__libc_current_sigrtmin.cpp
+++ b/libc/bionic/__libc_current_sigrtmin.cpp
@@ -28,14 +28,8 @@
#include <signal.h>
-// Realtime signals reserved for internal use:
-// 32 (__SIGRTMIN + 0) POSIX timers
-// 33 (__SIGRTMIN + 1) libbacktrace
-// 34 (__SIGRTMIN + 2) libcore
-// 35 (__SIGRTMIN + 3) debuggerd -b
+#include "private/sigrtmin.h"
-int __libc_current_sigrtmin(void) {
- // If you change this, also change __ndk_legacy___libc_current_sigrtmin
- // in <android/legacy_signal_inlines.h> to match.
- return __SIGRTMIN + 4;
+int __libc_current_sigrtmin() {
+ return __SIGRTMIN + __SIGRT_RESERVED;
}
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index 985d47f..944cfca 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -169,6 +169,12 @@
return ppoll(fds, fd_count, timeout, mask);
}
+int __ppoll64_chk(pollfd* fds, nfds_t fd_count, const timespec* timeout,
+ const sigset64_t* mask, size_t fds_size) {
+ __check_pollfd_array("ppoll64", fds_size, fd_count);
+ return ppoll64(fds, fd_count, timeout, mask);
+}
+
ssize_t __pread64_chk(int fd, void* buf, size_t count, off64_t offset, size_t buf_size) {
__check_count("pread64", "count", count);
__check_buffer_access("pread64", "write into", count, buf_size);
diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp
index 983fb32..ba59e8e 100644
--- a/libc/bionic/legacy_32_bit_support.cpp
+++ b/libc/bionic/legacy_32_bit_support.cpp
@@ -85,13 +85,13 @@
// to implement all four functions because the two system calls don't match any
// of the userspace functions. Unlike llseek, the pair is split lo-hi, not hi-lo.
ssize_t preadv(int fd, const struct iovec* ios, int count, off_t offset) {
- return __preadv64(fd, ios, count, offset, 0);
+ return preadv64(fd, ios, count, offset);
}
ssize_t preadv64(int fd, const struct iovec* ios, int count, off64_t offset) {
return __preadv64(fd, ios, count, offset, offset >> 32);
}
ssize_t pwritev(int fd, const struct iovec* ios, int count, off_t offset) {
- return __pwritev64(fd, ios, count, offset, 0);
+ return pwritev64(fd, ios, count, offset);
}
ssize_t pwritev64(int fd, const struct iovec* ios, int count, off64_t offset) {
return __pwritev64(fd, ios, count, offset, offset >> 32);
diff --git a/libc/bionic/poll.cpp b/libc/bionic/poll.cpp
index 1a54832..3df8b18 100644
--- a/libc/bionic/poll.cpp
+++ b/libc/bionic/poll.cpp
@@ -31,6 +31,7 @@
#include <sys/select.h>
#include "private/bionic_time_conversions.h"
+#include "private/sigrtmin.h"
#include "private/SigSetConverter.h"
extern "C" int __ppoll(pollfd*, unsigned int, timespec*, const sigset64_t*, size_t);
@@ -66,7 +67,15 @@
mutable_ts = *ts;
mutable_ts_ptr = &mutable_ts;
}
- return __ppoll(fds, fd_count, mutable_ts_ptr, ss, sizeof(*ss));
+
+ sigset64_t mutable_ss;
+ sigset64_t* mutable_ss_ptr = nullptr;
+ if (ss != nullptr) {
+ mutable_ss = filter_reserved_signals(*ss);
+ mutable_ss_ptr = &mutable_ss;
+ }
+
+ return __ppoll(fds, fd_count, mutable_ts_ptr, mutable_ss_ptr, sizeof(*mutable_ss_ptr));
}
int select(int fd_count, fd_set* read_fds, fd_set* write_fds, fd_set* error_fds, timeval* tv) {
@@ -109,6 +118,13 @@
mutable_ts_ptr = &mutable_ts;
}
+ sigset64_t mutable_ss;
+ sigset64_t* mutable_ss_ptr = nullptr;
+ if (ss != nullptr) {
+ mutable_ss = filter_reserved_signals(*ss);
+ mutable_ss_ptr = &mutable_ss;
+ }
+
// The Linux kernel only handles 6 arguments and this system call really needs 7,
// so the last argument is a void* pointing to:
struct pselect6_extra_data_t {
@@ -116,8 +132,8 @@
size_t ss_len;
};
pselect6_extra_data_t extra_data;
- extra_data.ss_addr = reinterpret_cast<uintptr_t>(ss);
- extra_data.ss_len = sizeof(*ss);
+ extra_data.ss_addr = reinterpret_cast<uintptr_t>(mutable_ss_ptr);
+ extra_data.ss_len = sizeof(*mutable_ss_ptr);
return __pselect6(fd_count, read_fds, write_fds, error_fds, mutable_ts_ptr, &extra_data);
}
diff --git a/libc/bionic/posix_timers.cpp b/libc/bionic/posix_timers.cpp
index 2edfe97..47d6db0 100644
--- a/libc/bionic/posix_timers.cpp
+++ b/libc/bionic/posix_timers.cpp
@@ -35,6 +35,8 @@
#include <time.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);
extern "C" int __timer_create(clockid_t, sigevent*, __kernel_timer_t*);
extern "C" int __timer_delete(__kernel_timer_t);
extern "C" int __timer_getoverrun(__kernel_timer_t);
@@ -77,7 +79,7 @@
while (true) {
// Wait for a signal...
siginfo_t si = {};
- if (sigtimedwait64(&sigset, &si, nullptr) == -1) continue;
+ if (__rt_sigtimedwait(&sigset, &si, nullptr, sizeof(sigset)) == -1) continue;
if (si.si_code == SI_TIMER) {
// This signal was sent because a timer fired, so call the callback.
@@ -146,11 +148,13 @@
sigset64_t sigset = {};
sigaddset64(&sigset, TIMER_SIGNAL);
sigset64_t old_sigset;
- sigprocmask64(SIG_BLOCK, &sigset, &old_sigset);
+
+ // Use __rt_sigprocmask instead of sigprocmask64 to avoid filtering out TIMER_SIGNAL.
+ __rt_sigprocmask(SIG_BLOCK, &sigset, &old_sigset, sizeof(sigset));
int rc = pthread_create(&timer->callback_thread, &thread_attributes, __timer_thread_start, timer);
- sigprocmask64(SIG_SETMASK, &old_sigset, nullptr);
+ __rt_sigprocmask(SIG_SETMASK, &old_sigset, nullptr, sizeof(old_sigset));
if (rc != 0) {
free(timer);
diff --git a/libc/bionic/pthread_cond.cpp b/libc/bionic/pthread_cond.cpp
index cbe67f9..a42506a 100644
--- a/libc/bionic/pthread_cond.cpp
+++ b/libc/bionic/pthread_cond.cpp
@@ -209,19 +209,18 @@
return __pthread_cond_timedwait(cond, mutex, cond->use_realtime_clock(), abstime);
}
+extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interface,
+ pthread_mutex_t* mutex,
+ const timespec* abs_timeout) {
+ return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout);
+}
+
#if !defined(__LP64__)
// TODO: this exists only for backward binary compatibility on 32 bit platforms.
extern "C" int pthread_cond_timedwait_monotonic(pthread_cond_t* cond_interface,
pthread_mutex_t* mutex,
const timespec* abs_timeout) {
-
- return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout);
-}
-
-extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interface,
- pthread_mutex_t* mutex,
- const timespec* abs_timeout) {
- return pthread_cond_timedwait_monotonic(cond_interface, mutex, abs_timeout);
+ return pthread_cond_timedwait_monotonic_np(cond_interface, mutex, abs_timeout);
}
// Force this function using CLOCK_MONOTONIC because it was always using
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index f1f7294..7f48972 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -40,7 +40,9 @@
#include "pthread_internal.h"
#include "private/bionic_constants.h"
+#include "private/bionic_fortify.h"
#include "private/bionic_futex.h"
+#include "private/bionic_sdk_version.h"
#include "private/bionic_systrace.h"
#include "private/bionic_time_conversions.h"
#include "private/bionic_tls.h"
@@ -171,9 +173,10 @@
return EBUSY;
}
-// Inlining this function in pthread_mutex_lock() add the cost of stack frame instructions on
+// Inlining this function in pthread_mutex_lock() adds the cost of stack frame instructions on
// ARM/ARM64, which increases at most 20 percent overhead. So make it noinline.
static int __attribute__((noinline)) PIMutexTimedLock(PIMutex& mutex,
+ bool use_realtime_clock,
const timespec* abs_timeout) {
int ret = PIMutexTryLock(mutex);
if (__predict_true(ret == 0)) {
@@ -181,7 +184,7 @@
}
if (ret == EBUSY) {
ScopedTrace trace("Contending for pthread mutex");
- ret = -__futex_pi_lock_ex(&mutex.owner_tid, mutex.shared, true, abs_timeout);
+ ret = -__futex_pi_lock_ex(&mutex.owner_tid, mutex.shared, use_realtime_clock, abs_timeout);
}
return ret;
}
@@ -413,7 +416,7 @@
#define MUTEX_TYPE_BITS_RECURSIVE MUTEX_TYPE_TO_BITS(PTHREAD_MUTEX_RECURSIVE)
#define MUTEX_TYPE_BITS_ERRORCHECK MUTEX_TYPE_TO_BITS(PTHREAD_MUTEX_ERRORCHECK)
// Use a special mutex type to mark priority inheritance mutexes.
-#define MUTEX_TYPE_BITS_WITH_PI MUTEX_TYPE_TO_BITS(3)
+#define PI_MUTEX_STATE MUTEX_TYPE_TO_BITS(3)
// For a PI mutex, it includes below fields:
// Atomic(uint16_t) state;
@@ -423,6 +426,7 @@
//
// bits: name description
// 15-14 type mutex type, should be 3
+// 13-0 padding should be 0
//
// pi_mutex holds the state of a PI mutex.
// pi_mutex_id holds an integer to find the state of a PI mutex.
@@ -533,7 +537,7 @@
}
mutex->pi_mutex_id = id;
#endif
- atomic_init(&mutex->state, MUTEX_TYPE_BITS_WITH_PI);
+ atomic_init(&mutex->state, PI_MUTEX_STATE);
PIMutex& pi_mutex = mutex->ToPIMutex();
pi_mutex.type = *attr & MUTEXATTR_TYPE_MASK;
pi_mutex.shared = (*attr & MUTEXATTR_SHARED_MASK) != 0;
@@ -777,6 +781,20 @@
} // namespace NonPI
+static inline __always_inline bool IsMutexDestroyed(uint16_t mutex_state) {
+ return mutex_state == 0xffff;
+}
+
+// Inlining this function in pthread_mutex_lock() adds the cost of stack frame instructions on
+// ARM64. So make it noinline.
+static int __attribute__((noinline)) HandleUsingDestroyedMutex(pthread_mutex_t* mutex,
+ const char* function_name) {
+ if (bionic_get_application_target_sdk_version() >= __ANDROID_API_P__) {
+ __fortify_fatal("%s called on a destroyed mutex (%p)", function_name, mutex);
+ }
+ return EBUSY;
+}
+
int pthread_mutex_lock(pthread_mutex_t* mutex_interface) {
#if !defined(__LP64__)
// Some apps depend on being able to pass NULL as a mutex and get EINVAL
@@ -788,7 +806,6 @@
#endif
pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
-
uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
uint16_t mtype = (old_state & MUTEX_TYPE_MASK);
// Avoid slowing down fast path of normal mutex lock operation.
@@ -797,13 +814,17 @@
if (__predict_true(NonPI::NormalMutexTryLock(mutex, shared) == 0)) {
return 0;
}
- } else if (mtype == MUTEX_TYPE_BITS_WITH_PI) {
+ }
+ if (old_state == PI_MUTEX_STATE) {
PIMutex& m = mutex->ToPIMutex();
// Handle common case first.
if (__predict_true(PIMutexTryLock(m) == 0)) {
return 0;
}
- return PIMutexTimedLock(mutex->ToPIMutex(), nullptr);
+ return PIMutexTimedLock(mutex->ToPIMutex(), false, nullptr);
+ }
+ if (__predict_false(IsMutexDestroyed(old_state))) {
+ return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__);
}
return NonPI::MutexLockWithTimeout(mutex, false, nullptr);
}
@@ -819,7 +840,6 @@
#endif
pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
-
uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
uint16_t mtype = (old_state & MUTEX_TYPE_MASK);
uint16_t shared = (old_state & MUTEX_SHARED_MASK);
@@ -829,9 +849,12 @@
NonPI::NormalMutexUnlock(mutex, shared);
return 0;
}
- if (mtype == MUTEX_TYPE_BITS_WITH_PI) {
+ if (old_state == PI_MUTEX_STATE) {
return PIMutexUnlock(mutex->ToPIMutex());
}
+ if (__predict_false(IsMutexDestroyed(old_state))) {
+ return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__);
+ }
// Do we already own this recursive or error-check mutex?
pid_t tid = __get_thread()->tid;
@@ -875,9 +898,12 @@
uint16_t shared = (old_state & MUTEX_SHARED_MASK);
return NonPI::NormalMutexTryLock(mutex, shared);
}
- if (mtype == MUTEX_TYPE_BITS_WITH_PI) {
+ if (old_state == PI_MUTEX_STATE) {
return PIMutexTryLock(mutex->ToPIMutex());
}
+ if (__predict_false(IsMutexDestroyed(old_state))) {
+ return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__);
+ }
// Do we already own this recursive or error-check mutex?
pid_t tid = __get_thread()->tid;
@@ -923,7 +949,8 @@
}
#endif
-int pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, const timespec* abs_timeout) {
+static int __pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, bool use_realtime_clock,
+ const timespec* abs_timeout, const char* function) {
pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
uint16_t mtype = (old_state & MUTEX_TYPE_MASK);
@@ -934,21 +961,31 @@
return 0;
}
}
- if (mtype == MUTEX_TYPE_BITS_WITH_PI) {
- return PIMutexTimedLock(mutex->ToPIMutex(), abs_timeout);
+ if (old_state == PI_MUTEX_STATE) {
+ return PIMutexTimedLock(mutex->ToPIMutex(), use_realtime_clock, abs_timeout);
}
- return NonPI::MutexLockWithTimeout(mutex, true, abs_timeout);
+ if (__predict_false(IsMutexDestroyed(old_state))) {
+ return HandleUsingDestroyedMutex(mutex_interface, function);
+ }
+ return NonPI::MutexLockWithTimeout(mutex, use_realtime_clock, abs_timeout);
+}
+
+int pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, const struct timespec* abs_timeout) {
+ return __pthread_mutex_timedlock(mutex_interface, true, abs_timeout, __FUNCTION__);
+}
+
+int pthread_mutex_timedlock_monotonic_np(pthread_mutex_t* mutex_interface,
+ const struct timespec* abs_timeout) {
+ return __pthread_mutex_timedlock(mutex_interface, false, abs_timeout, __FUNCTION__);
}
int pthread_mutex_destroy(pthread_mutex_t* mutex_interface) {
pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
- if (old_state == 0xffff) {
- // The mutex has been destroyed.
- return EBUSY;
+ if (__predict_false(IsMutexDestroyed(old_state))) {
+ return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__);
}
- uint16_t mtype = (old_state & MUTEX_TYPE_MASK);
- if (mtype == MUTEX_TYPE_BITS_WITH_PI) {
+ if (old_state == PI_MUTEX_STATE) {
int result = PIMutexDestroy(mutex->ToPIMutex());
if (result == 0) {
mutex->FreePIMutex();
diff --git a/libc/bionic/pthread_rwlock.cpp b/libc/bionic/pthread_rwlock.cpp
index a065295..4f4c461 100644
--- a/libc/bionic/pthread_rwlock.cpp
+++ b/libc/bionic/pthread_rwlock.cpp
@@ -286,9 +286,8 @@
return EBUSY;
}
-static int __pthread_rwlock_timedrdlock(pthread_rwlock_internal_t* rwlock,
+static int __pthread_rwlock_timedrdlock(pthread_rwlock_internal_t* rwlock, bool use_realtime_clock,
const timespec* abs_timeout_or_null) {
-
if (atomic_load_explicit(&rwlock->writer_tid, memory_order_relaxed) == __get_thread()->tid) {
return EDEADLK;
}
@@ -324,7 +323,7 @@
int futex_result = 0;
if (!__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred)) {
futex_result = __futex_wait_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared,
- old_serial, true, abs_timeout_or_null);
+ old_serial, use_realtime_clock, abs_timeout_or_null);
}
rwlock->pending_lock.lock();
@@ -359,9 +358,8 @@
return EBUSY;
}
-static int __pthread_rwlock_timedwrlock(pthread_rwlock_internal_t* rwlock,
+static int __pthread_rwlock_timedwrlock(pthread_rwlock_internal_t* rwlock, bool use_realtime_clock,
const timespec* abs_timeout_or_null) {
-
if (atomic_load_explicit(&rwlock->writer_tid, memory_order_relaxed) == __get_thread()->tid) {
return EDEADLK;
}
@@ -392,7 +390,7 @@
int futex_result = 0;
if (!__can_acquire_write_lock(old_state)) {
futex_result = __futex_wait_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared,
- old_serial, true, abs_timeout_or_null);
+ old_serial, use_realtime_clock, abs_timeout_or_null);
}
rwlock->pending_lock.lock();
@@ -415,13 +413,20 @@
if (__predict_true(__pthread_rwlock_tryrdlock(rwlock) == 0)) {
return 0;
}
- return __pthread_rwlock_timedrdlock(rwlock, nullptr);
+ return __pthread_rwlock_timedrdlock(rwlock, false, nullptr);
}
int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) {
pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
- return __pthread_rwlock_timedrdlock(rwlock, abs_timeout);
+ return __pthread_rwlock_timedrdlock(rwlock, true, abs_timeout);
+}
+
+int pthread_rwlock_timedrdlock_monotonic_np(pthread_rwlock_t* rwlock_interface,
+ const timespec* abs_timeout) {
+ pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
+
+ return __pthread_rwlock_timedrdlock(rwlock, false, abs_timeout);
}
int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock_interface) {
@@ -434,13 +439,20 @@
if (__predict_true(__pthread_rwlock_trywrlock(rwlock) == 0)) {
return 0;
}
- return __pthread_rwlock_timedwrlock(rwlock, nullptr);
+ return __pthread_rwlock_timedwrlock(rwlock, false, nullptr);
}
int pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) {
pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
- return __pthread_rwlock_timedwrlock(rwlock, abs_timeout);
+ return __pthread_rwlock_timedwrlock(rwlock, true, abs_timeout);
+}
+
+int pthread_rwlock_timedwrlock_monotonic_np(pthread_rwlock_t* rwlock_interface,
+ const timespec* abs_timeout) {
+ pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
+
+ return __pthread_rwlock_timedwrlock(rwlock, false, abs_timeout);
}
int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock_interface) {
diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp
index 610a1b2..d401b66 100644
--- a/libc/bionic/semaphore.cpp
+++ b/libc/bionic/semaphore.cpp
@@ -231,7 +231,7 @@
}
}
-int sem_timedwait(sem_t* sem, const timespec* abs_timeout) {
+static int __sem_timedwait(sem_t* sem, const timespec* abs_timeout, bool use_realtime_clock) {
atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem);
// POSIX says we need to try to decrement the semaphore
@@ -257,7 +257,8 @@
}
// Contention detected. Wait for a wakeup event.
- int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, true, abs_timeout);
+ int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE,
+ use_realtime_clock, abs_timeout);
// Return in case of timeout or interrupt.
if (result == -ETIMEDOUT || result == -EINTR) {
@@ -267,6 +268,14 @@
}
}
+int sem_timedwait(sem_t* sem, const timespec* abs_timeout) {
+ return __sem_timedwait(sem, abs_timeout, true);
+}
+
+int sem_timedwait_monotonic_np(sem_t* sem, const timespec* abs_timeout) {
+ return __sem_timedwait(sem, abs_timeout, false);
+}
+
int sem_post(sem_t* sem) {
atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem);
unsigned int shared = SEM_GET_SHARED(sem_count_ptr);
diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp
index 19a08e6..41923cf 100644
--- a/libc/bionic/sigaction.cpp
+++ b/libc/bionic/sigaction.cpp
@@ -29,6 +29,8 @@
#include <signal.h>
#include <string.h>
+#include "private/sigrtmin.h"
+
extern "C" void __restore_rt(void);
extern "C" void __restore(void);
@@ -41,7 +43,7 @@
if (bionic_new_action != NULL) {
kernel_new_action.sa_flags = bionic_new_action->sa_flags;
kernel_new_action.sa_handler = bionic_new_action->sa_handler;
- kernel_new_action.sa_mask = bionic_new_action->sa_mask;
+ kernel_new_action.sa_mask = filter_reserved_signals(bionic_new_action->sa_mask);
#if defined(SA_RESTORER)
kernel_new_action.sa_restorer = bionic_new_action->sa_restorer;
#if defined(__aarch64__)
@@ -120,6 +122,7 @@
kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
}
#endif
+ kernel_new.sa_mask = filter_reserved_signals(kernel_new.sa_mask);
}
return __rt_sigaction(signal,
diff --git a/libc/bionic/signal.cpp b/libc/bionic/signal.cpp
index fbfe0ce..175182b 100644
--- a/libc/bionic/signal.cpp
+++ b/libc/bionic/signal.cpp
@@ -38,9 +38,9 @@
#include "private/ErrnoRestorer.h"
#include "private/SigSetConverter.h"
+#include "private/sigrtmin.h"
extern "C" int __rt_sigpending(const sigset64_t*, size_t);
-extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t);
extern "C" int ___rt_sigqueueinfo(pid_t, int, siginfo_t*);
extern "C" int __rt_sigsuspend(const sigset64_t*, size_t);
extern "C" int __rt_sigtimedwait(const sigset64_t*, siginfo_t*, const timespec*, size_t);
@@ -208,31 +208,6 @@
return __rt_sigpending(set, sizeof(*set));
}
-int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
- SigSetConverter new_set;
- sigset64_t* new_set_ptr = nullptr;
- if (bionic_new_set != nullptr) {
- sigemptyset64(&new_set.sigset64);
- new_set.sigset = *bionic_new_set;
- new_set_ptr = &new_set.sigset64;
- }
-
- SigSetConverter old_set;
- if (sigprocmask64(how, new_set_ptr, &old_set.sigset64) == -1) {
- return -1;
- }
-
- if (bionic_old_set != nullptr) {
- *bionic_old_set = old_set.sigset;
- }
-
- return 0;
-}
-
-int sigprocmask64(int how, const sigset64_t* new_set, sigset64_t* old_set) {
- return __rt_sigprocmask(how, new_set, old_set, sizeof(*new_set));
-}
-
int sigqueue(pid_t pid, int sig, const sigval value) {
siginfo_t info;
memset(&info, 0, sizeof(siginfo_t));
@@ -281,21 +256,33 @@
int sigsuspend(const sigset_t* bionic_set) {
SigSetConverter set = {};
set.sigset = *bionic_set;
- return __rt_sigsuspend(&set.sigset64, sizeof(set.sigset64));
+ return sigsuspend64(&set.sigset64);
}
int sigsuspend64(const sigset64_t* set) {
- return __rt_sigsuspend(set, sizeof(*set));
+ sigset64_t mutable_set;
+ sigset64_t* mutable_set_ptr = nullptr;
+ if (set) {
+ mutable_set = filter_reserved_signals(*set);
+ mutable_set_ptr = &mutable_set;
+ }
+ return __rt_sigsuspend(mutable_set_ptr, sizeof(*set));
}
int sigtimedwait(const sigset_t* bionic_set, siginfo_t* info, const timespec* timeout) {
SigSetConverter set = {};
set.sigset = *bionic_set;
- return __rt_sigtimedwait(&set.sigset64, info, timeout, sizeof(set.sigset64));
+ return sigtimedwait64(&set.sigset64, info, timeout);
}
int sigtimedwait64(const sigset64_t* set, siginfo_t* info, const timespec* timeout) {
- return __rt_sigtimedwait(set, info, timeout, sizeof(*set));
+ sigset64_t mutable_set;
+ sigset64_t* mutable_set_ptr = nullptr;
+ if (set) {
+ mutable_set = filter_reserved_signals(*set);
+ mutable_set_ptr = &mutable_set;
+ }
+ return __rt_sigtimedwait(mutable_set_ptr, info, timeout, sizeof(*set));
}
int sigwait(const sigset_t* bionic_set, int* sig) {
diff --git a/libc/bionic/sigprocmask.cpp b/libc/bionic/sigprocmask.cpp
new file mode 100644
index 0000000..36866f3
--- /dev/null
+++ b/libc/bionic/sigprocmask.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+
+#include "private/sigrtmin.h"
+#include "private/SigSetConverter.h"
+
+extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t);
+
+//
+// These need to be kept separate from pthread_sigmask, sigblock, sigsetmask,
+// sighold, and sigset because libsigchain only intercepts sigprocmask so we
+// can't allow clang to decide to inline sigprocmask.
+//
+
+int sigprocmask(int how,
+ const sigset_t* bionic_new_set,
+ sigset_t* bionic_old_set) __attribute__((__noinline__)) {
+ SigSetConverter new_set;
+ sigset64_t* new_set_ptr = nullptr;
+ if (bionic_new_set != nullptr) {
+ sigemptyset64(&new_set.sigset64);
+ new_set.sigset = *bionic_new_set;
+ new_set_ptr = &new_set.sigset64;
+ }
+
+ SigSetConverter old_set;
+ if (sigprocmask64(how, new_set_ptr, &old_set.sigset64) == -1) {
+ return -1;
+ }
+
+ if (bionic_old_set != nullptr) {
+ *bionic_old_set = old_set.sigset;
+ }
+
+ return 0;
+}
+
+int sigprocmask64(int how,
+ const sigset64_t* new_set,
+ sigset64_t* old_set) __attribute__((__noinline__)) {
+ sigset64_t mutable_new_set;
+ sigset64_t* mutable_new_set_ptr = nullptr;
+ if (new_set) {
+ mutable_new_set = filter_reserved_signals(*new_set);
+ mutable_new_set_ptr = &mutable_new_set;
+ }
+ return __rt_sigprocmask(how, mutable_new_set_ptr, old_set, sizeof(*new_set));
+}
diff --git a/libc/bionic/system.cpp b/libc/bionic/system.cpp
new file mode 100644
index 0000000..7411ae5
--- /dev/null
+++ b/libc/bionic/system.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <spawn.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "private/ScopedSignalBlocker.h"
+#include "private/ScopedSignalHandler.h"
+
+int system(const char* command) {
+ // "The system() function shall always return non-zero when command is NULL."
+ // http://pubs.opengroup.org/onlinepubs/9699919799/functions/system.html
+ if (command == nullptr) return 1;
+
+ ScopedSignalBlocker sigchld_blocker(SIGCHLD);
+ ScopedSignalHandler sigint_ignorer(SIGINT, SIG_IGN);
+ ScopedSignalHandler sigquit_ignorer(SIGQUIT, SIG_IGN);
+
+ sigset64_t default_mask = {};
+ if (sigint_ignorer.old_action_.sa_handler != SIG_IGN) sigaddset64(&default_mask, SIGINT);
+ if (sigquit_ignorer.old_action_.sa_handler != SIG_IGN) sigaddset64(&default_mask, SIGQUIT);
+
+ static constexpr int flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
+ posix_spawnattr_t attributes;
+ if ((errno = posix_spawnattr_init(&attributes))) return -1;
+ if ((errno = posix_spawnattr_setsigdefault64(&attributes, &default_mask))) return -1;
+ if ((errno = posix_spawnattr_setsigmask64(&attributes, &sigchld_blocker.old_set_))) return -1;
+ if ((errno = posix_spawnattr_setflags(&attributes, flags))) return -1;
+
+ const char* argv[] = { "sh", "-c", command, nullptr };
+ pid_t child;
+ if ((errno = posix_spawn(&child, _PATH_BSHELL, nullptr, &attributes,
+ const_cast<char**>(argv), environ)) != 0) {
+ return -1;
+ }
+
+ posix_spawnattr_destroy(&attributes);
+
+ int status;
+ pid_t pid = TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
+ return (pid == -1 ? -1 : status);
+}
diff --git a/libc/dns/include/resolv_netid.h b/libc/dns/include/resolv_netid.h
index 3b2f4da..c7e2823 100644
--- a/libc/dns/include/resolv_netid.h
+++ b/libc/dns/include/resolv_netid.h
@@ -72,11 +72,15 @@
unsigned dns_netid;
unsigned dns_mark;
uid_t uid;
+ unsigned flags;
res_send_qhook qhook;
};
#define NET_CONTEXT_INVALID_UID ((uid_t)-1)
+#define NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS 0x00000001
+#define NET_CONTEXT_FLAG_USE_EDNS 0x00000002
+
struct hostent *android_gethostbyaddrfornet(const void *, socklen_t, int, unsigned, unsigned) __used_in_netd;
struct hostent *android_gethostbynamefornet(const char *, int, unsigned, unsigned) __used_in_netd;
int android_getaddrinfofornet(const char *, const char *, const struct addrinfo *, unsigned,
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
index 418bf6d..f1488a9 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -107,6 +107,7 @@
#include <syslog.h>
#include <stdarg.h>
#include "nsswitch.h"
+#include "private/bionic_defs.h"
typedef union sockaddr_union {
struct sockaddr generic;
@@ -198,7 +199,7 @@
{ 0, 0 }
};
-#define MAXPACKET (64*1024)
+#define MAXPACKET (8*1024)
typedef union {
HEADER hdr;
@@ -310,6 +311,7 @@
#define MATCH(x, y, w) \
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
const char *
gai_strerror(int ecode)
{
@@ -318,6 +320,7 @@
return ai_errlist[ecode];
}
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
void
freeaddrinfo(struct addrinfo *ai)
{
@@ -556,6 +559,7 @@
}
#endif
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
@@ -563,6 +567,7 @@
return android_getaddrinfofornet(hostname, servname, hints, NETID_UNSET, MARK_UNSET, res);
}
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
android_getaddrinfofornet(const char *hostname, const char *servname,
const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res)
@@ -577,6 +582,7 @@
return android_getaddrinfofornetcontext(hostname, servname, hints, &netcontext, res);
}
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int
android_getaddrinfofornetcontext(const char *hostname, const char *servname,
const struct addrinfo *hints, const struct android_net_context *netcontext,
@@ -2171,8 +2177,12 @@
int class, type;
u_char *answer;
int anslen;
+ u_int oflags;
hp = (HEADER *)(void *)t->answer;
+ oflags = res->_flags;
+
+again:
hp->rcode = NOERROR; /* default */
/* make it easier... */
@@ -2188,7 +2198,8 @@
n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
buf, sizeof(buf));
#ifdef RES_USE_EDNS0
- if (n > 0 && (res->options & RES_USE_EDNS0) != 0)
+ if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 &&
+ (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
n = res_nopt(res, n, buf, sizeof(buf), anslen);
#endif
if (n <= 0) {
@@ -2213,6 +2224,18 @@
if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
rcode = hp->rcode; /* record most recent error */
+#ifdef RES_USE_EDNS0
+ /* if the query choked with EDNS0, retry without EDNS0 */
+ if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0 &&
+ ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) {
+ res->_flags |= RES_F_EDNS0ERR;
+#ifdef DEBUG
+ if (res->options & RES_DEBUG)
+ printf(";; res_nquery: retry without EDNS0\n");
+#endif
+ goto again;
+ }
+#endif
#ifdef DEBUG
if (res->options & RES_DEBUG)
printf(";; rcode = %u, ancount=%u\n", hp->rcode,
diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
index 7118a29..7589380 100644
--- a/libc/dns/net/gethnamaddr.c
+++ b/libc/dns/net/gethnamaddr.c
@@ -127,7 +127,7 @@
.uid = NET_CONTEXT_INVALID_UID
};
-#define MAXPACKET (64*1024)
+#define MAXPACKET (8*1024)
typedef union {
HEADER hdr;
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index 9c65570..dda8694 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -591,12 +591,12 @@
/* QR must be set to 0, opcode must be 0 and AA must be 0 */
/* RA, Z, and RCODE must be 0 */
- if ((p[2] & 0xFC) != 0 || p[3] != 0) {
+ if ((p[2] & 0xFC) != 0 || (p[3] & 0xCF) != 0) {
XLOG("query packet flags unsupported");
return 0;
}
- /* Note that we ignore the TC and RD bits here for the
+ /* Note that we ignore the TC, RD, CD, and AD bits here for the
* following reasons:
*
* - there is no point for a query packet sent to a server
@@ -606,11 +606,11 @@
* _resolv_cache_add. We should not freak out if this
* is the case.
*
- * - we consider that the result from a RD=0 or a RD=1
- * query might be different, hence that the RD bit
+ * - we consider that the result from a query might depend on
+ * the RD, AD, and CD bits, so these bits
* should be used to differentiate cached result.
*
- * this implies that RD is checked when hashing or
+ * this implies that these bits are checked when hashing or
* comparing query packets, but not TC
*/
@@ -620,7 +620,7 @@
dnCount = (p[8] << 8) | p[9];
arCount = (p[10]<< 8) | p[11];
- if (anCount != 0 || dnCount != 0 || arCount != 0) {
+ if (anCount != 0 || dnCount != 0 || arCount > 1) {
XLOG("query packet contains non-query records");
return 0;
}
@@ -817,12 +817,26 @@
}
static unsigned
+_dnsPacket_hashRR( DnsPacket* packet, unsigned hash )
+{
+ int rdlength;
+ hash = _dnsPacket_hashQR(packet, hash);
+ hash = _dnsPacket_hashBytes(packet, 4, hash); /* TTL */
+ rdlength = _dnsPacket_readInt16(packet);
+ hash = _dnsPacket_hashBytes(packet, rdlength, hash); /* RDATA */
+ return hash;
+}
+
+static unsigned
_dnsPacket_hashQuery( DnsPacket* packet )
{
unsigned hash = FNV_BASIS;
- int count;
+ int count, arcount;
_dnsPacket_rewind(packet);
+ /* ignore the ID */
+ _dnsPacket_skip(packet, 2);
+
/* we ignore the TC bit for reasons explained in
* _dnsPacket_checkQuery().
*
@@ -832,19 +846,29 @@
*/
hash = hash*FNV_MULT ^ (packet->base[2] & 1);
- /* assume: other flags are 0 */
- _dnsPacket_skip(packet, 4);
+ /* mark the first header byte as processed */
+ _dnsPacket_skip(packet, 1);
+
+ /* process the second header byte */
+ hash = _dnsPacket_hashBytes(packet, 1, hash);
/* read QDCOUNT */
count = _dnsPacket_readInt16(packet);
- /* assume: ANcount, NScount, ARcount are 0 */
- _dnsPacket_skip(packet, 6);
+ /* assume: ANcount and NScount are 0 */
+ _dnsPacket_skip(packet, 4);
+
+ /* read ARCOUNT */
+ arcount = _dnsPacket_readInt16(packet);
/* hash QDCOUNT QRs */
for ( ; count > 0; count-- )
hash = _dnsPacket_hashQR(packet, hash);
+ /* hash ARCOUNT RRs */
+ for ( ; arcount > 0; arcount-- )
+ hash = _dnsPacket_hashRR(packet, hash);
+
return hash;
}
@@ -929,9 +953,28 @@
}
static int
+_dnsPacket_isEqualRR( DnsPacket* pack1, DnsPacket* pack2 )
+{
+ int rdlength1, rdlength2;
+ /* compare query + TTL */
+ if ( !_dnsPacket_isEqualQR(pack1, pack2) ||
+ !_dnsPacket_isEqualBytes(pack1, pack2, 4) )
+ return 0;
+
+ /* compare RDATA */
+ rdlength1 = _dnsPacket_readInt16(pack1);
+ rdlength2 = _dnsPacket_readInt16(pack2);
+ if ( rdlength1 != rdlength2 ||
+ !_dnsPacket_isEqualBytes(pack1, pack2, rdlength1) )
+ return 0;
+
+ return 1;
+}
+
+static int
_dnsPacket_isEqualQuery( DnsPacket* pack1, DnsPacket* pack2 )
{
- int count1, count2;
+ int count1, count2, arcount1, arcount2;
/* compare the headers, ignore most fields */
_dnsPacket_rewind(pack1);
@@ -943,7 +986,12 @@
return 0;
}
- /* assume: other flags are all 0 */
+ if (pack1->base[3] != pack2->base[3]) {
+ XLOG("different CD or AD");
+ return 0;
+ }
+
+ /* mark ID and header bytes as compared */
_dnsPacket_skip(pack1, 4);
_dnsPacket_skip(pack2, 4);
@@ -955,9 +1003,17 @@
return 0;
}
- /* assume: ANcount, NScount and ARcount are all 0 */
- _dnsPacket_skip(pack1, 6);
- _dnsPacket_skip(pack2, 6);
+ /* assume: ANcount and NScount are 0 */
+ _dnsPacket_skip(pack1, 4);
+ _dnsPacket_skip(pack2, 4);
+
+ /* compare ARCOUNT */
+ arcount1 = _dnsPacket_readInt16(pack1);
+ arcount2 = _dnsPacket_readInt16(pack2);
+ if (arcount1 != arcount2 || arcount1 < 0) {
+ XLOG("different ARCOUNT");
+ return 0;
+ }
/* compare the QDCOUNT QRs */
for ( ; count1 > 0; count1-- ) {
@@ -966,6 +1022,14 @@
return 0;
}
}
+
+ /* compare the ARCOUNT RRs */
+ for ( ; arcount1 > 0; arcount1-- ) {
+ if (!_dnsPacket_isEqualRR(pack1, pack2)) {
+ XLOG("different additional RR");
+ return 0;
+ }
+ }
return 1;
}
diff --git a/libc/dns/resolv/res_init.c b/libc/dns/resolv/res_init.c
index 302a62b..2fb2a3d 100644
--- a/libc/dns/resolv/res_init.c
+++ b/libc/dns/resolv/res_init.c
@@ -774,6 +774,9 @@
statp->netid = netcontext->dns_netid;
statp->_mark = netcontext->dns_mark;
statp->qhook = netcontext->qhook;
+ if (netcontext->flags & NET_CONTEXT_FLAG_USE_EDNS) {
+ statp->options |= RES_USE_EDNS0 | RES_USE_DNSSEC;
+ }
}
}
diff --git a/libc/dns/resolv/res_mkquery.c b/libc/dns/resolv/res_mkquery.c
index 6fb1957..c73d588 100644
--- a/libc/dns/resolv/res_mkquery.c
+++ b/libc/dns/resolv/res_mkquery.c
@@ -145,6 +145,7 @@
hp->id = htons(res_randomid());
hp->opcode = op;
hp->rd = (statp->options & RES_RECURSE) != 0U;
+ hp->ad = (statp->options & RES_USE_DNSSEC) != 0U;
hp->rcode = NOERROR;
cp = buf + HFIXEDSZ;
ep = buf + buflen;
@@ -253,7 +254,9 @@
ns_put16(T_OPT, cp); /* TYPE */
cp += INT16SZ;
- ns_put16(anslen & 0xffff, cp); /* CLASS = UDP payload size */
+ if (anslen > 0xffff)
+ anslen = 0xffff;
+ ns_put16(anslen, cp); /* CLASS = UDP payload size */
cp += INT16SZ;
*cp++ = NOERROR; /* extended RCODE */
*cp++ = 0; /* EDNS version */
diff --git a/libc/include/bits/fortify/poll.h b/libc/include/bits/fortify/poll.h
index 8363e35..c3ae31d 100644
--- a/libc/include/bits/fortify/poll.h
+++ b/libc/include/bits/fortify/poll.h
@@ -31,8 +31,8 @@
#endif
int __poll_chk(struct pollfd*, nfds_t, int, size_t) __INTRODUCED_IN(23);
-int __ppoll_chk(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*, size_t)
- __INTRODUCED_IN(23);
+int __ppoll_chk(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*, size_t) __INTRODUCED_IN(23);
+int __ppoll64_chk(struct pollfd*, nfds_t, const struct timespec*, const sigset64_t*, size_t) __INTRODUCED_IN(28);
#if defined(__BIONIC_FORTIFY)
#if __ANDROID_API__ >= __ANDROID_API_M__
@@ -64,7 +64,24 @@
}
return __ppoll_chk(fds, fd_count, timeout, mask, bos_fds);
}
-#else /* defined(__clang__) */
+
+#if __ANDROID_API__ >= __ANDROID_API_P__
+__BIONIC_FORTIFY_INLINE
+int ppoll64(struct pollfd* const fds __pass_object_size, nfds_t fd_count, const struct timespec* timeout, const sigset64_t* mask)
+ __overloadable
+ __clang_error_if(__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(fds) < sizeof(*fds) * fd_count,
+ "in call to 'ppoll64', fd_count is larger than the given buffer") {
+ size_t bos_fds = __bos(fds);
+
+ if (bos_fds == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __call_bypassing_fortify(ppoll64)(fds, fd_count, timeout, mask);
+ }
+ return __ppoll64_chk(fds, fd_count, timeout, mask, bos_fds);
+}
+#endif
+
+#else /* !defined(__clang__) */
int __poll_real(struct pollfd*, nfds_t, int) __RENAME(poll);
__errordecl(__poll_too_small_error, "poll: pollfd array smaller than fd count");
diff --git a/libc/include/bits/ioctl.h b/libc/include/bits/ioctl.h
index 0cf87d2..3357c1b 100644
--- a/libc/include/bits/ioctl.h
+++ b/libc/include/bits/ioctl.h
@@ -35,6 +35,28 @@
int ioctl(int __fd, int __request, ...);
+/*
+ * Work around unsigned -> signed conversion warnings: many common ioctl
+ * constants are unsigned.
+ *
+ * Since this workaround introduces an overload to ioctl, it's possible that it
+ * will break existing code that takes the address of ioctl. If such a breakage
+ * occurs, you can work around it by either:
+ * - specifying a concrete, correct type for ioctl (whether it be through a cast
+ * in `(int (*)(int, int, ...))ioctl`, creating a temporary variable with the
+ * type of the ioctl you prefer, ...), or
+ * - defining BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD, which will make the
+ * overloading go away.
+ *
+ * FIXME: __has_extension is more or less a clang version check. Remove it when
+ * we don't need to support old clang code.
+ */
+#if defined(__clang__) && __has_extension(overloadable_unmarked) && \
+ !defined(BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD)
+/* enable_if(1) just exists to break overloading ties. */
+int ioctl(int __fd, unsigned __request, ...) __overloadable __enable_if(1, "") __RENAME(ioctl);
+#endif
+
__END_DECLS
#endif
diff --git a/libc/include/elf.h b/libc/include/elf.h
index a8d62db..f5b2091 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -260,6 +260,8 @@
#define DT_ANDROID_RELASZ (DT_LOOS + 5)
#define DT_GNU_HASH 0x6ffffef5
+#define DT_TLSDESC_PLT 0x6ffffef6
+#define DT_TLSDESC_GOT 0x6ffffef7
/* http://www.sco.com/developers/gabi/latest/ch4.eheader.html */
#define EI_ABIVERSION 8
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 8d95a3b..46898d6 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -54,6 +54,9 @@
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP { { ((PTHREAD_MUTEX_ERRORCHECK & 3) << 14) } }
#define PTHREAD_COND_INITIALIZER { { 0 } }
+#if __ANDROID_API__ >= __ANDROID_API_L__
+#define PTHREAD_COND_INITIALIZER_MONOTONIC_NP { { 1 << 1 } }
+#endif
#define PTHREAD_RWLOCK_INITIALIZER { { 0 } }
@@ -122,6 +125,16 @@
int pthread_cond_init(pthread_cond_t* __cond, const pthread_condattr_t* __attr);
int pthread_cond_signal(pthread_cond_t* __cond);
int pthread_cond_timedwait(pthread_cond_t* __cond, pthread_mutex_t* __mutex, const struct timespec* __timeout);
+/*
+ * Condition variables use CLOCK_REALTIME by default for their timeouts, however that is
+ * typically inappropriate, since that clock can change dramatically, causing the timeout to
+ * either expire earlier or much later than intended.
+ * Condition variables have an initialization option to use CLOCK_MONOTONIC, and in addition,
+ * Android provides this API to use CLOCK_MONOTONIC on a condition variable for this single wait
+ * no matter how it was initialized.
+ */
+int pthread_cond_timedwait_monotonic_np(pthread_cond_t* __cond, pthread_mutex_t* __mutex,
+ const struct timespec* __timeout) __INTRODUCED_IN_64(28);
int pthread_cond_wait(pthread_cond_t* __cond, pthread_mutex_t* __mutex);
int pthread_create(pthread_t* __pthread_ptr, pthread_attr_t const* __attr, void* (*__start_routine)(void*), void*);
@@ -159,6 +172,16 @@
int pthread_mutex_lock(pthread_mutex_t* __mutex);
int pthread_mutex_timedlock(pthread_mutex_t* __mutex, const struct timespec* __timeout)
__INTRODUCED_IN(21);
+
+/*
+ * POSIX only supports using pthread_mutex_timedlock() with CLOCK_REALTIME, however that is
+ * typically inappropriate, since that clock can change dramatically, causing the timeout to
+ * either expire earlier or much later than intended.
+ * This function is added to use a timespec based on CLOCK_MONOTONIC that does not suffer
+ * from this issue.
+ */
+int pthread_mutex_timedlock_monotonic_np(pthread_mutex_t* __mutex, const struct timespec* __timeout)
+ __INTRODUCED_IN(28);
int pthread_mutex_trylock(pthread_mutex_t* __mutex);
int pthread_mutex_unlock(pthread_mutex_t* __mutex);
@@ -176,7 +199,6 @@
*/
int pthread_mutex_lock_timeout_np(pthread_mutex_t* __mutex, unsigned __timeout_ms);
int pthread_cond_timeout_np(pthread_cond_t* __cond, pthread_mutex_t* __mutex, unsigned __timeout_ms);
-int pthread_cond_timedwait_monotonic_np(pthread_cond_t* __cond, pthread_mutex_t* __mutex, const struct timespec* __timeout);
int pthread_cond_timedwait_relative_np(pthread_cond_t* __cond, pthread_mutex_t* __mutex, const struct timespec* __relative_timeout);
#endif
@@ -194,7 +216,13 @@
int pthread_rwlock_init(pthread_rwlock_t* __rwlock, const pthread_rwlockattr_t* __attr);
int pthread_rwlock_rdlock(pthread_rwlock_t* __rwlock);
int pthread_rwlock_timedrdlock(pthread_rwlock_t* __rwlock, const struct timespec* __timeout);
+/* See the comment on pthread_mutex_timedlock_monotonic_np for usage of this function. */
+int pthread_rwlock_timedrdlock_monotonic_np(pthread_rwlock_t* __rwlock,
+ const struct timespec* __timeout) __INTRODUCED_IN(28);
int pthread_rwlock_timedwrlock(pthread_rwlock_t* __rwlock, const struct timespec* __timeout);
+/* See the comment on pthread_mutex_timedlock_monotonic_np for usage of this function. */
+int pthread_rwlock_timedwrlock_monotonic_np(pthread_rwlock_t* __rwlock,
+ const struct timespec* __timeout) __INTRODUCED_IN(28);
int pthread_rwlock_tryrdlock(pthread_rwlock_t* __rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t* __rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t* __rwlock);
diff --git a/libc/include/semaphore.h b/libc/include/semaphore.h
index 7e3dc1c..01d685b 100644
--- a/libc/include/semaphore.h
+++ b/libc/include/semaphore.h
@@ -49,6 +49,13 @@
int sem_init(sem_t* __sem, int __shared, unsigned int __value);
int sem_post(sem_t* __sem);
int sem_timedwait(sem_t* __sem, const struct timespec* __ts);
+/*
+ * POSIX only supports using sem_timedwait() with CLOCK_REALTIME, however that is typically
+ * inappropriate, since that clock can change dramatically, causing the timeout to either
+ * expire earlier or much later than intended. This function is added to use a timespec based
+ * on CLOCK_MONOTONIC that does not suffer from this issue.
+ */
+int sem_timedwait_monotonic_np(sem_t* __sem, const struct timespec* __ts) __INTRODUCED_IN(28);
int sem_trywait(sem_t* __sem);
int sem_wait(sem_t* __sem);
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index c270bb5..5760689 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -343,21 +343,7 @@
# define __BIONIC_INCLUDE_FORTIFY_HEADERS 1
#endif
-/*
- * Used to support clangisms with FORTIFY. Because these change how symbols are
- * emitted, we need to ensure that bionic itself is built fortified. But lots
- * of external code (especially stuff using configure) likes to declare
- * functions directly, and they can't know that the overloadable attribute
- * exists. This leads to errors like:
- *
- * dcigettext.c:151:7: error: redeclaration of 'getcwd' must have the 'overloadable' attribute
- * char *getcwd ();
- * ^
- *
- * To avoid this and keep such software building, don't use overloadable if
- * we're not using fortify.
- */
-#if defined(__clang__) && defined(__BIONIC_FORTIFY)
+#if defined(__clang__)
# define __overloadable __attribute__((overloadable))
#else
# define __overloadable
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 19c80b7..56e4189 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -115,6 +115,7 @@
__poll_chk; # introduced=23
__ppoll; # arm x86 mips introduced=21
__ppoll_chk; # introduced=23
+ __ppoll64_chk; # introduced=28
__pread64_chk; # introduced=23
__pread_chk; # introduced=23
__progname; # var
@@ -745,7 +746,7 @@
pthread_cond_signal;
pthread_cond_timedwait;
pthread_cond_timedwait_monotonic; # arm x86 mips
- pthread_cond_timedwait_monotonic_np; # arm x86 mips
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_timedwait_relative_np; # arm x86 mips
pthread_cond_timeout_np; # arm x86 mips
pthread_cond_wait;
@@ -1385,10 +1386,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index cab66e6..880ed80 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -74,6 +74,7 @@
__p_type_syms; # var
__poll_chk; # introduced=23
__ppoll_chk; # introduced=23
+ __ppoll64_chk; # introduced=28
__pread64_chk; # introduced=23
__pread_chk; # introduced=23
__progname; # var
@@ -691,6 +692,7 @@
pthread_cond_init;
pthread_cond_signal;
pthread_cond_timedwait;
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_wait;
pthread_condattr_destroy;
pthread_condattr_getclock; # introduced=21
@@ -1305,10 +1307,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 65e4802..b787ea5 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -115,6 +115,7 @@
__poll_chk; # introduced=23
__ppoll; # arm x86 mips introduced=21
__ppoll_chk; # introduced=23
+ __ppoll64_chk; # introduced=28
__pread64_chk; # introduced=23
__pread_chk; # introduced=23
__progname; # var
@@ -770,7 +771,7 @@
pthread_cond_signal;
pthread_cond_timedwait;
pthread_cond_timedwait_monotonic; # arm x86 mips
- pthread_cond_timedwait_monotonic_np; # arm x86 mips
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_timedwait_relative_np; # arm x86 mips
pthread_cond_timeout_np; # arm x86 mips
pthread_cond_wait;
@@ -1410,10 +1411,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 363a55a..ec3fe3a 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -112,6 +112,7 @@
__poll_chk; # introduced=23
__ppoll; # arm x86 mips introduced=21
__ppoll_chk; # introduced=23
+ __ppoll64_chk; # introduced=28
__pread64_chk; # introduced=23
__pread_chk; # introduced=23
__progname; # var
@@ -743,7 +744,7 @@
pthread_cond_signal;
pthread_cond_timedwait;
pthread_cond_timedwait_monotonic; # arm x86 mips
- pthread_cond_timedwait_monotonic_np; # arm x86 mips
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_timedwait_relative_np; # arm x86 mips
pthread_cond_timeout_np; # arm x86 mips
pthread_cond_wait;
@@ -1369,10 +1370,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index cab66e6..880ed80 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -74,6 +74,7 @@
__p_type_syms; # var
__poll_chk; # introduced=23
__ppoll_chk; # introduced=23
+ __ppoll64_chk; # introduced=28
__pread64_chk; # introduced=23
__pread_chk; # introduced=23
__progname; # var
@@ -691,6 +692,7 @@
pthread_cond_init;
pthread_cond_signal;
pthread_cond_timedwait;
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_wait;
pthread_condattr_destroy;
pthread_condattr_getclock; # introduced=21
@@ -1305,10 +1307,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index fc5e463..9407b58 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -112,6 +112,7 @@
__poll_chk; # introduced=23
__ppoll; # arm x86 mips introduced=21
__ppoll_chk; # introduced=23
+ __ppoll64_chk; # introduced=28
__pread64_chk; # introduced=23
__pread_chk; # introduced=23
__progname; # var
@@ -741,7 +742,7 @@
pthread_cond_signal;
pthread_cond_timedwait;
pthread_cond_timedwait_monotonic; # arm x86 mips
- pthread_cond_timedwait_monotonic_np; # arm x86 mips
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_timedwait_relative_np; # arm x86 mips
pthread_cond_timeout_np; # arm x86 mips
pthread_cond_wait;
@@ -1367,10 +1368,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index cab66e6..880ed80 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -74,6 +74,7 @@
__p_type_syms; # var
__poll_chk; # introduced=23
__ppoll_chk; # introduced=23
+ __ppoll64_chk; # introduced=28
__pread64_chk; # introduced=23
__pread_chk; # introduced=23
__progname; # var
@@ -691,6 +692,7 @@
pthread_cond_init;
pthread_cond_signal;
pthread_cond_timedwait;
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_wait;
pthread_condattr_destroy;
pthread_condattr_getclock; # introduced=21
@@ -1305,10 +1307,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/private/ScopedSignalBlocker.h b/libc/private/ScopedSignalBlocker.h
index 7582068..d1cf629 100644
--- a/libc/private/ScopedSignalBlocker.h
+++ b/libc/private/ScopedSignalBlocker.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef SCOPED_SIGNAL_BLOCKER_H
-#define SCOPED_SIGNAL_BLOCKER_H
+#pragma once
#include <signal.h>
@@ -23,10 +22,18 @@
class ScopedSignalBlocker {
public:
+ // Block all signals.
explicit ScopedSignalBlocker() {
sigset64_t set;
sigfillset64(&set);
- sigprocmask64(SIG_SETMASK, &set, &old_set_);
+ sigprocmask64(SIG_BLOCK, &set, &old_set_);
+ }
+
+ // Block just the specified signal.
+ explicit ScopedSignalBlocker(int signal) {
+ sigset64_t set = {};
+ sigaddset64(&set, signal);
+ sigprocmask64(SIG_BLOCK, &set, &old_set_);
}
~ScopedSignalBlocker() {
@@ -37,10 +44,7 @@
sigprocmask64(SIG_SETMASK, &old_set_, nullptr);
}
- private:
sigset64_t old_set_;
DISALLOW_COPY_AND_ASSIGN(ScopedSignalBlocker);
};
-
-#endif
diff --git a/libc/private/ScopedSignalHandler.h b/libc/private/ScopedSignalHandler.h
new file mode 100644
index 0000000..dd5823f
--- /dev/null
+++ b/libc/private/ScopedSignalHandler.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <signal.h>
+
+class ScopedSignalHandler {
+ public:
+ ScopedSignalHandler(int signal_number, void (*handler)(int), int sa_flags = 0)
+ : signal_number_(signal_number) {
+ action_ = { .sa_flags = sa_flags, .sa_handler = handler };
+ sigaction64(signal_number_, &action_, &old_action_);
+ }
+
+ ScopedSignalHandler(int signal_number, void (*action)(int, siginfo_t*, void*),
+ int sa_flags = SA_SIGINFO)
+ : signal_number_(signal_number) {
+ action_ = { .sa_flags = sa_flags, .sa_sigaction = action };
+ sigaction64(signal_number_, &action_, &old_action_);
+ }
+
+ ScopedSignalHandler(int signal_number) : signal_number_(signal_number) {
+ sigaction64(signal_number, nullptr, &old_action_);
+ }
+
+ ~ScopedSignalHandler() {
+ sigaction64(signal_number_, &old_action_, nullptr);
+ }
+
+ struct sigaction64 action_;
+ struct sigaction64 old_action_;
+ const int signal_number_;
+};
diff --git a/libc/private/bionic_fortify.h b/libc/private/bionic_fortify.h
index 7f22963..3c3292e 100644
--- a/libc/private/bionic_fortify.h
+++ b/libc/private/bionic_fortify.h
@@ -52,7 +52,7 @@
__fortify_fatal("%s: file descriptor %d < 0", fn, fd);
}
if (__predict_false(fd >= FD_SETSIZE)) {
- __fortify_fatal("%s: file descriptor %d >= FD_SETSIZE %zu", fn, fd, set_size);
+ __fortify_fatal("%s: file descriptor %d >= FD_SETSIZE %zu", fn, fd, FD_SETSIZE);
}
if (__predict_false(set_size < sizeof(fd_set))) {
__fortify_fatal("%s: set size %zu is too small to be an fd_set", fn, set_size);
diff --git a/libc/private/sigrtmin.h b/libc/private/sigrtmin.h
new file mode 100644
index 0000000..ea8673d
--- /dev/null
+++ b/libc/private/sigrtmin.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+#include <signal.h>
+
+// Realtime signals reserved for internal use:
+// 32 (__SIGRTMIN + 0) POSIX timers
+// 33 (__SIGRTMIN + 1) libbacktrace
+// 34 (__SIGRTMIN + 2) libcore
+// 35 (__SIGRTMIN + 3) debuggerd -b
+//
+// If you change this, also change __ndk_legacy___libc_current_sigrtmin
+// in <android/legacy_signal_inlines.h> to match.
+
+#define __SIGRT_RESERVED 4
+static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset) {
+ for (int signo = __SIGRTMIN; signo < __SIGRTMIN + __SIGRT_RESERVED; ++signo) {
+ sigdelset64(&sigset, signo);
+ }
+ return sigset;
+}
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index 11b136d..441fcfe 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -38,12 +38,10 @@
#include <stdbool.h>
#include <wchar.h>
-#if defined(__cplusplus) // Until we fork all of stdio...
+#if defined(__cplusplus) // Until we fork all of stdio...
#include "private/bionic_fortify.h"
#endif
-#include "wcio.h"
-
/*
* Information local to this implementation of stdio,
* in particular, macros and private variables.
@@ -61,53 +59,66 @@
};
struct __sFILE {
- unsigned char *_p; /* current position in (some) buffer */
- int _r; /* read space left for getc() */
- int _w; /* write space left for putc() */
+ unsigned char* _p; /* current position in (some) buffer */
+ int _r; /* read space left for getc() */
+ int _w; /* write space left for putc() */
#if defined(__LP64__)
- int _flags; /* flags, below; this FILE is free if 0 */
- int _file; /* fileno, if Unix descriptor, else -1 */
+ int _flags; /* flags, below; this FILE is free if 0 */
+ int _file; /* fileno, if Unix descriptor, else -1 */
#else
- short _flags; /* flags, below; this FILE is free if 0 */
- short _file; /* fileno, if Unix descriptor, else -1 */
+ short _flags; /* flags, below; this FILE is free if 0 */
+ short _file; /* fileno, if Unix descriptor, else -1 */
#endif
- struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
- int _lbfsize; /* 0 or -_bf._size, for inline putc */
+ struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
+ int _lbfsize; /* 0 or -_bf._size, for inline putc */
- // Function pointers used by `funopen`.
- // Note that `_seek` is ignored if `_seek64` (in __sfileext) is set.
- // TODO: NetBSD has `funopen2` which corrects the `int`s to `size_t`s.
- // TODO: glibc has `fopencookie` which passes the function pointers in a struct.
- void* _cookie; /* cookie passed to io functions */
- int (*_close)(void*);
- int (*_read)(void*, char*, int);
- fpos_t (*_seek)(void*, fpos_t, int);
- int (*_write)(void*, const char*, int);
+ // Function pointers used by `funopen`.
+ // Note that `_seek` is ignored if `_seek64` (in __sfileext) is set.
+ // TODO: NetBSD has `funopen2` which corrects the `int`s to `size_t`s.
+ // TODO: glibc has `fopencookie` which passes the function pointers in a struct.
+ void* _cookie; /* cookie passed to io functions */
+ int (*_close)(void*);
+ int (*_read)(void*, char*, int);
+ fpos_t (*_seek)(void*, fpos_t, int);
+ int (*_write)(void*, const char*, int);
- /* extension data, to avoid further ABI breakage */
- struct __sbuf _ext;
- /* data for long sequences of ungetc() */
- unsigned char *_up; /* saved _p when _p is doing ungetc data */
- int _ur; /* saved _r when _r is counting ungetc data */
+ /* extension data, to avoid further ABI breakage */
+ struct __sbuf _ext;
+ /* data for long sequences of ungetc() */
+ unsigned char* _up; /* saved _p when _p is doing ungetc data */
+ int _ur; /* saved _r when _r is counting ungetc data */
- /* tricks to meet minimum requirements even when malloc() fails */
- unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
- unsigned char _nbuf[1]; /* guarantee a getc() buffer */
+ /* tricks to meet minimum requirements even when malloc() fails */
+ unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
+ unsigned char _nbuf[1]; /* guarantee a getc() buffer */
- /* separate buffer for fgetln() when line crosses buffer boundary */
- struct __sbuf _lb; /* buffer for fgetln() */
+ /* separate buffer for fgetln() when line crosses buffer boundary */
+ struct __sbuf _lb; /* buffer for fgetln() */
- /* Unix stdio files get aligned to block boundaries on fseek() */
- int _blksize; /* stat.st_blksize (may be != _bf._size) */
+ /* Unix stdio files get aligned to block boundaries on fseek() */
+ int _blksize; /* stat.st_blksize (may be != _bf._size) */
- fpos_t _unused_0; // This was the `_offset` field (see below).
+ fpos_t _unused_0; // This was the `_offset` field (see below).
- // Do not add new fields here. (Or remove or change the size of any above.)
- // Although bionic currently exports `stdin`, `stdout`, and `stderr` symbols,
- // that still hasn't made it to the NDK. All NDK-built apps index directly
- // into an array of this struct (which was in <stdio.h> historically), so if
- // you need to make any changes, they need to be in the `__sfileext` struct
- // below, and accessed via `_EXT`.
+ // Do not add new fields here. (Or remove or change the size of any above.)
+ // Although bionic currently exports `stdin`, `stdout`, and `stderr` symbols,
+ // that still hasn't made it to the NDK. All NDK-built apps index directly
+ // into an array of this struct (which was in <stdio.h> historically), so if
+ // you need to make any changes, they need to be in the `__sfileext` struct
+ // below, and accessed via `_EXT`.
+};
+
+/* minimal requirement of SUSv2 */
+#define WCIO_UNGETWC_BUFSIZE 1
+
+struct wchar_io_data {
+ mbstate_t wcio_mbstate_in;
+ mbstate_t wcio_mbstate_out;
+
+ wchar_t wcio_ungetwc_buf[WCIO_UNGETWC_BUFSIZE];
+ size_t wcio_ungetwc_inbuf;
+
+ int wcio_mode; /* orientation */
};
struct __sfileext {
@@ -133,9 +144,9 @@
#define __SNBF 0x0002 // Unbuffered.
// __SRD and __SWR are mutually exclusive because they indicate what we did last.
// If you want to know whether we were opened read-write, check __SRW instead.
-#define __SRD 0x0004 // Last operation was read.
-#define __SWR 0x0008 // Last operation was write.
-#define __SRW 0x0010 // Was opened for reading & writing.
+#define __SRD 0x0004 // Last operation was read.
+#define __SWR 0x0008 // Last operation was write.
+#define __SRW 0x0010 // Was opened for reading & writing.
#define __SEOF 0x0020 // Found EOF.
#define __SERR 0x0040 // Found error.
#define __SMBF 0x0080 // `_buf` is from malloc.
@@ -156,13 +167,13 @@
#define _EXT(fp) __BIONIC_CAST(reinterpret_cast, struct __sfileext*, (fp)->_ext._base)
#define _UB(fp) _EXT(fp)->_ub
-#define _FLOCK(fp) _EXT(fp)->_lock
+#define _FLOCK(fp) _EXT(fp)->_lock
-#define _FILEEXT_SETUP(fp, fext) \
- do { \
+#define _FILEEXT_SETUP(fp, fext) \
+ do { \
(fp)->_ext._base = __BIONIC_CAST(reinterpret_cast, unsigned char*, fext); \
- memset(_EXT(fp), 0, sizeof(struct __sfileext)); \
- _EXT(fp)->_caller_handles_locking = true; \
+ memset(_EXT(fp), 0, sizeof(struct __sfileext)); \
+ _EXT(fp)->_caller_handles_locking = true; \
} while (0)
// Android <= 19 had getc/putc macros in <stdio.h> that referred
@@ -182,49 +193,47 @@
__LIBC32_LEGACY_PUBLIC__ void __smakebuf(FILE*);
/* These are referenced by the Greed for Glory franchise. */
-__LIBC32_LEGACY_PUBLIC__ int __sflush(FILE *);
-__LIBC32_LEGACY_PUBLIC__ int __sread(void *, char *, int);
-__LIBC32_LEGACY_PUBLIC__ int __swrite(void *, const char *, int);
-__LIBC32_LEGACY_PUBLIC__ fpos_t __sseek(void *, fpos_t, int);
-__LIBC32_LEGACY_PUBLIC__ int __sclose(void *);
-__LIBC32_LEGACY_PUBLIC__ int _fwalk(int (*)(FILE *));
+__LIBC32_LEGACY_PUBLIC__ int __sflush(FILE*);
+__LIBC32_LEGACY_PUBLIC__ int __sread(void*, char*, int);
+__LIBC32_LEGACY_PUBLIC__ int __swrite(void*, const char*, int);
+__LIBC32_LEGACY_PUBLIC__ fpos_t __sseek(void*, fpos_t, int);
+__LIBC32_LEGACY_PUBLIC__ int __sclose(void*);
+__LIBC32_LEGACY_PUBLIC__ int _fwalk(int (*)(FILE*));
off64_t __sseek64(void*, off64_t, int);
-int __sflush_locked(FILE *);
-int __swhatbuf(FILE *, size_t *, int *);
-wint_t __fgetwc_unlock(FILE *);
-wint_t __ungetwc(wint_t, FILE *);
-int __vfprintf(FILE *, const char *, va_list);
-int __svfscanf(FILE *, const char *, va_list);
-int __vfwprintf(FILE *, const wchar_t *, va_list);
-int __vfwscanf(FILE *, const wchar_t *, va_list);
+int __sflush_locked(FILE*);
+int __swhatbuf(FILE*, size_t*, int*);
+wint_t __fgetwc_unlock(FILE*);
+wint_t __ungetwc(wint_t, FILE*);
+int __vfprintf(FILE*, const char*, va_list);
+int __svfscanf(FILE*, const char*, va_list);
+int __vfwprintf(FILE*, const wchar_t*, va_list);
+int __vfwscanf(FILE*, const wchar_t*, va_list);
/*
* Return true if the given FILE cannot be written now.
*/
-#define cantwrite(fp) \
- ((((fp)->_flags & __SWR) == 0 || (fp)->_bf._base == NULL) && \
- __swsetup(fp))
+#define cantwrite(fp) ((((fp)->_flags & __SWR) == 0 || (fp)->_bf._base == NULL) && __swsetup(fp))
/*
* Test whether the given stdio file has an active ungetc buffer;
* release such a buffer, without restoring ordinary unread data.
*/
-#define HASUB(fp) (_UB(fp)._base != NULL)
-#define FREEUB(fp) { \
- if (_UB(fp)._base != (fp)->_ubuf) \
- free(_UB(fp)._base); \
- _UB(fp)._base = NULL; \
-}
+#define HASUB(fp) (_UB(fp)._base != NULL)
+#define FREEUB(fp) \
+ { \
+ if (_UB(fp)._base != (fp)->_ubuf) free(_UB(fp)._base); \
+ _UB(fp)._base = NULL; \
+ }
-#define FLOCKFILE(fp) if (!_EXT(fp)->_caller_handles_locking) flockfile(fp)
-#define FUNLOCKFILE(fp) if (!_EXT(fp)->_caller_handles_locking) funlockfile(fp)
-
-#define NO_PRINTF_PERCENT_N
+#define FLOCKFILE(fp) \
+ if (!_EXT(fp)->_caller_handles_locking) flockfile(fp)
+#define FUNLOCKFILE(fp) \
+ if (!_EXT(fp)->_caller_handles_locking) funlockfile(fp)
/* OpenBSD exposes these in <stdio.h>, but we only want them exposed to the implementation. */
-#define __sferror(p) (((p)->_flags & __SERR) != 0)
-#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
+#define __sferror(p) (((p)->_flags & __SERR) != 0)
+#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR | __SEOF)))
#define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
/* OpenBSD declares these in fvwrite.h, but we share them with C++ parts of the implementation. */
@@ -241,7 +250,7 @@
wint_t __fputwc_unlock(wchar_t wc, FILE* fp);
/* Remove the if (!__sdidinit) __sinit() idiom from untouched upstream stdio code. */
-extern void __sinit(void); // Not actually implemented.
+extern void __sinit(void); // Not actually implemented.
#define __sdidinit 1
size_t parsefloat(FILE*, char*, char*);
@@ -249,7 +258,8 @@
// Sanity check a FILE* for nullptr, so we can emit a message while crashing
// instead of doing a blind null-dereference.
-#define CHECK_FP(fp) if (fp == nullptr) __fortify_fatal("%s: null FILE*", __FUNCTION__)
+#define CHECK_FP(fp) \
+ if (fp == nullptr) __fortify_fatal("%s: null FILE*", __FUNCTION__)
/*
* Floating point scanf/printf (input/output) definitions.
@@ -276,4 +286,21 @@
char* __hldtoa(long double, const char*, int, int*, int*, char**);
char* __ldtoa(long double*, int, int, int*, int*, char**);
+#define WCIO_GET(fp) (_EXT(fp) ? &(_EXT(fp)->_wcio) : (struct wchar_io_data*)0)
+
+#define _SET_ORIENTATION(fp, mode) \
+ do { \
+ struct wchar_io_data* _wcio = WCIO_GET(fp); \
+ if (_wcio && _wcio->wcio_mode == 0) _wcio->wcio_mode = (mode); \
+ } while (0)
+
+#define WCIO_FREE(fp) \
+ do { \
+ struct wchar_io_data* _wcio = WCIO_GET(fp); \
+ if (_wcio) { \
+ _wcio->wcio_mode = 0; \
+ _wcio->wcio_ungetwc_inbuf = 0; \
+ } \
+ } while (0)
+
__END_DECLS
diff --git a/libc/stdio/printf_common.h b/libc/stdio/printf_common.h
index 050120e..85c91de 100644
--- a/libc/stdio/printf_common.h
+++ b/libc/stdio/printf_common.h
@@ -499,24 +499,8 @@
else
ADDTYPE(T_DOUBLE);
break;
-#ifndef NO_PRINTF_PERCENT_N
case 'n':
- if (flags & LLONGINT)
- ADDTYPE(TP_LLONG);
- else if (flags & LONGINT)
- ADDTYPE(TP_LONG);
- else if (flags & SHORTINT)
- ADDTYPE(TP_SHORT);
- else if (flags & PTRINT)
- ADDTYPE(TP_PTRINT);
- else if (flags & SIZEINT)
- ADDTYPE(TP_SSIZEINT);
- else if (flags & MAXINT)
- ADDTYPE(TP_MAXINT);
- else
- ADDTYPE(TP_INT);
- continue; /* no output */
-#endif /* NO_PRINTF_PERCENT_N */
+ __fortify_fatal("%%n not allowed on Android");
case 'O':
flags |= LONGINT;
/*FALLTHROUGH*/
diff --git a/libc/stdio/vfprintf.cpp b/libc/stdio/vfprintf.cpp
index 9182880..17e4372 100644
--- a/libc/stdio/vfprintf.cpp
+++ b/libc/stdio/vfprintf.cpp
@@ -449,26 +449,8 @@
lead = expt;
}
break;
-#ifndef NO_PRINTF_PERCENT_N
case 'n':
- if (flags & LLONGINT)
- *GETARG(long long*) = ret;
- else if (flags & LONGINT)
- *GETARG(long*) = ret;
- else if (flags & SHORTINT)
- *GETARG(short*) = ret;
- else if (flags & CHARINT)
- *GETARG(signed char*) = ret;
- else if (flags & PTRINT)
- *GETARG(ptrdiff_t*) = ret;
- else if (flags & SIZEINT)
- *GETARG(ssize_t*) = ret;
- else if (flags & MAXINT)
- *GETARG(intmax_t*) = ret;
- else
- *GETARG(int*) = ret;
- continue; /* no output */
-#endif /* NO_PRINTF_PERCENT_N */
+ __fortify_fatal("%%n not allowed on Android");
case 'O':
flags |= LONGINT;
/*FALLTHROUGH*/
diff --git a/libc/stdio/vfwprintf.cpp b/libc/stdio/vfwprintf.cpp
index 7a00202..46b6233 100644
--- a/libc/stdio/vfwprintf.cpp
+++ b/libc/stdio/vfwprintf.cpp
@@ -434,26 +434,8 @@
lead = expt;
}
break;
-#ifndef NO_PRINTF_PERCENT_N
case 'n':
- if (flags & LLONGINT)
- *GETARG(long long*) = ret;
- else if (flags & LONGINT)
- *GETARG(long*) = ret;
- else if (flags & SHORTINT)
- *GETARG(short*) = ret;
- else if (flags & CHARINT)
- *GETARG(signed char*) = ret;
- else if (flags & PTRINT)
- *GETARG(ptrdiff_t*) = ret;
- else if (flags & SIZEINT)
- *GETARG(ssize_t*) = ret;
- else if (flags & MAXINT)
- *GETARG(intmax_t*) = ret;
- else
- *GETARG(int*) = ret;
- continue; /* no output */
-#endif /* NO_PRINTF_PERCENT_N */
+ __fortify_fatal("%%n not allowed on Android");
case 'O':
flags |= LONGINT;
/*FALLTHROUGH*/
diff --git a/libc/stdio/wcio.h b/libc/stdio/wcio.h
deleted file mode 100644
index 047eb77..0000000
--- a/libc/stdio/wcio.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* $OpenBSD: wcio.h,v 1.2 2013/04/17 17:40:35 tedu Exp $ */
-/* $NetBSD: wcio.h,v 1.3 2003/01/18 11:30:00 thorpej Exp $ */
-
-/*-
- * Copyright (c)2001 Citrus Project,
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Citrus$
- */
-
-#pragma once
-
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* minimal requirement of SUSv2 */
-#define WCIO_UNGETWC_BUFSIZE 1
-
-struct wchar_io_data {
- mbstate_t wcio_mbstate_in;
- mbstate_t wcio_mbstate_out;
-
- wchar_t wcio_ungetwc_buf[WCIO_UNGETWC_BUFSIZE];
- size_t wcio_ungetwc_inbuf;
-
- int wcio_mode; /* orientation */
-};
-
-#define WCIO_GET(fp) \
- (_EXT(fp) ? &(_EXT(fp)->_wcio) : (struct wchar_io_data *)0)
-
-#define _SET_ORIENTATION(fp, mode) \
-do {\
- struct wchar_io_data *_wcio = WCIO_GET(fp); \
- if (_wcio && _wcio->wcio_mode == 0) \
- _wcio->wcio_mode = (mode);\
-} while (0)
-
-/*
- * WCIO_FREE should be called by fclose
- */
-#define WCIO_FREE(fp) \
-do {\
- struct wchar_io_data *_wcio = WCIO_GET(fp); \
- if (_wcio) { \
- _wcio->wcio_mode = 0;\
- _wcio->wcio_ungetwc_inbuf = 0;\
- } \
-} while (0)
-
-#define WCIO_FREEUB(fp) \
-do {\
- struct wchar_io_data *_wcio = WCIO_GET(fp); \
- if (_wcio) { \
- _wcio->wcio_ungetwc_inbuf = 0;\
- } \
-} while (0)
-
-__END_DECLS
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index 2100630..0e9a7d3 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -38,7 +38,9 @@
//#include <sys/localedef.h>
#include <ctype.h>
+#include <errno.h>
#include <locale.h>
+#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tzfile.h"
@@ -128,7 +130,7 @@
fmt++;
continue;
}
-
+
if ((c = *fmt++) != '%')
goto literal;
@@ -154,7 +156,7 @@
_LEGAL_ALT(0);
alt_format |= _ALT_O;
goto again;
-
+
/*
* "Complex" conversion rules, implemented through recursion.
*/
@@ -169,7 +171,7 @@
if (!(bp = _strptime(bp, "%m/%d/%y", tm, cr)))
return (NULL);
break;
-
+
case 'R': /* The time as "%H:%M". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
@@ -337,6 +339,25 @@
return (NULL);
break;
+ case 's':
+ {
+ // Android addition, based on FreeBSD's implementation.
+ int saved_errno = errno;
+ errno = 0;
+ const unsigned char* old_bp = bp;
+ long n = strtol((const char*) bp, (char**) &bp, 10);
+ time_t t = n;
+ if (bp == old_bp || errno == ERANGE || ((long) t) != n) {
+ errno = saved_errno;
+ return NULL;
+ }
+ errno = saved_errno;
+
+ if (localtime_r(&t, tm) == NULL) return NULL;
+ }
+ break;
+
+
case 'U': /* The week of year, beginning on sunday. */
case 'W': /* The week of year, beginning on monday. */
_LEGAL_ALT(_ALT_O);
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/system.c b/libc/upstream-openbsd/lib/libc/stdlib/system.c
deleted file mode 100644
index de32d43..0000000
--- a/libc/upstream-openbsd/lib/libc/stdlib/system.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/* $OpenBSD: system.c,v 1.11 2015/10/23 04:44:41 guenther Exp $ */
-/*
- * Copyright (c) 1988 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <paths.h>
-
-extern char **environ;
-
-int
-system(const char *command)
-{
- pid_t pid, cpid;
- struct sigaction intsave, quitsave;
- sigset_t mask, omask;
- int pstat;
- char *argp[] = {"sh", "-c", NULL, NULL};
-
- if (!command) /* just checking... */
- return(1);
-
- argp[2] = (char *)command;
-
- sigemptyset(&mask);
- sigaddset(&mask, SIGCHLD);
- sigprocmask(SIG_BLOCK, &mask, &omask);
- switch (cpid = vfork()) {
- case -1: /* error */
- sigprocmask(SIG_SETMASK, &omask, NULL);
- return(-1);
- case 0: /* child */
- sigprocmask(SIG_SETMASK, &omask, NULL);
- execve(_PATH_BSHELL, argp, environ);
- _exit(127);
- }
-
- sigaction(SIGINT, NULL, &intsave);
- sigaction(SIGQUIT, NULL, &quitsave);
- do {
- pid = waitpid(cpid, &pstat, 0);
- } while (pid == -1 && errno == EINTR);
- sigprocmask(SIG_SETMASK, &omask, NULL);
- sigaction(SIGINT, &intsave, NULL);
- sigaction(SIGQUIT, &quitsave, NULL);
- return (pid == -1 ? -1 : pstat);
-}
-DEF_STRONG(system);
diff --git a/libm/Android.bp b/libm/Android.bp
index 76a4699..9d318fa 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -515,12 +515,14 @@
"-D_BSD_SOURCE",
"-DFLT_EVAL_METHOD=0",
"-include freebsd-compat.h",
+ "-Wall",
"-Werror",
"-Wno-missing-braces",
"-Wno-parentheses",
"-Wno-sign-compare",
- "-Wno-uninitialized",
"-Wno-unknown-pragmas",
+ "-Wno-unused-const-variable",
+ "-Wno-unused-variable",
],
include_dirs: ["bionic/libc"],
diff --git a/linker/linker.cpp b/linker/linker.cpp
index ff2a7e6..32df911 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1105,10 +1105,14 @@
const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
#if !defined(__LP64__)
// Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
- if (get_application_target_sdk_version() < __ANDROID_API_M__) {
+ int app_target_api_level = get_application_target_sdk_version();
+ if (app_target_api_level < __ANDROID_API_M__) {
const char* bname = basename(dt_needed);
if (bname != dt_needed) {
- DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
+ DL_WARN_documented_change(__ANDROID_API_M__,
+ "invalid-dt_needed-entries-enforced-for-api-level-23",
+ "library \"%s\" has invalid DT_NEEDED entry \"%s\"",
+ sopath, dt_needed, app_target_api_level);
add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
}
@@ -1246,10 +1250,11 @@
const soinfo* needed_or_dlopened_by = task->get_needed_by();
const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
needed_or_dlopened_by->get_realpath();
- DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
- " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
- " will be removed in future releases of Android.",
- name, realpath.c_str(), sopath, ns->get_name());
+ DL_WARN_documented_change(__ANDROID_API_N__,
+ "private-api-enforced-for-api-level-24",
+ "library \"%s\" (\"%s\") needed or dlopened by \"%s\" "
+ "is not accessible by namespace \"%s\"",
+ name, realpath.c_str(), sopath, ns->get_name());
add_dlwarning(sopath, "unauthorized access to", name);
}
} else {
@@ -2779,6 +2784,11 @@
}
}
#endif
+ if (ELF_ST_TYPE(s->st_info) == STT_TLS) {
+ DL_ERR("unsupported ELF TLS symbol \"%s\" referenced by \"%s\"",
+ sym_name, get_realpath());
+ return false;
+ }
sym_addr = lsi->resolve_symbol_address(s);
#if !defined(__LP64__)
if (protect_segments) {
@@ -3363,7 +3373,9 @@
set_dt_flags_1(d->d_un.d_val);
if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
- DL_WARN("\"%s\" has unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
+ DL_WARN("Warning: \"%s\" has unsupported flags DT_FLAGS_1=%p "
+ "(ignoring unsupported flags)",
+ get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
}
break;
#if defined(__mips__)
@@ -3430,6 +3442,11 @@
default:
if (!relocating_linker) {
+ if (d->d_tag == DT_TLSDESC_GOT || d->d_tag == DT_TLSDESC_PLT) {
+ DL_ERR("unsupported ELF TLS DT entry in \"%s\"", get_realpath());
+ return false;
+ }
+
const char* tag_name;
if (d->d_tag == DT_RPATH) {
tag_name = "DT_RPATH";
@@ -3442,7 +3459,7 @@
} else {
tag_name = "unknown";
}
- DL_WARN("\"%s\" unused DT entry: %s (type %p arg %p)",
+ DL_WARN("Warning: \"%s\" unused DT entry: %s (type %p arg %p) (ignoring)",
get_realpath(),
tag_name,
reinterpret_cast<void*>(d->d_tag),
@@ -3495,16 +3512,20 @@
// Before M release linker was using basename in place of soname.
// In the case when dt_soname is absent some apps stop working
// because they can't find dt_needed library by soname.
- // This workaround should keep them working. (applies only
- // for apps targeting sdk version < M). Make an exception for
- // the main executable and linker; they do not need to have dt_soname
+ // This workaround should keep them working. (Applies only
+ // for apps targeting sdk version < M.) Make an exception for
+ // the main executable and linker; they do not need to have dt_soname.
+ // TODO: >= O the linker doesn't need this workaround.
if (soname_ == nullptr &&
this != solist_get_somain() &&
(flags_ & FLAG_LINKER) == 0 &&
get_application_target_sdk_version() < __ANDROID_API_M__) {
soname_ = basename(realpath_.c_str());
- DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
- get_realpath(), soname_);
+ DL_WARN_documented_change(__ANDROID_API_M__,
+ "missing-soname-enforced-for-api-level-23",
+ "\"%s\" has no DT_SONAME (will use %s instead)",
+ get_realpath(), soname_);
+
// Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI
}
return true;
@@ -3535,7 +3556,8 @@
#if !defined(__LP64__)
if (has_text_relocations) {
// Fail if app is targeting M or above.
- if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
+ int app_target_api_level = get_application_target_sdk_version();
+ if (app_target_api_level >= __ANDROID_API_M__) {
DL_ERR_AND_LOG("\"%s\" has text relocations (https://android.googlesource.com/platform/"
"bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-"
"Enforced-for-API-level-23)", get_realpath());
@@ -3543,13 +3565,13 @@
}
// Make segments writable to allow text relocations to work properly. We will later call
// phdr_table_protect_segments() after all of them are applied.
- DL_WARN("\"%s\" has text relocations (https://android.googlesource.com/platform/"
- "bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-Enforced-"
- "for-API-level-23)", get_realpath());
+ DL_WARN_documented_change(__ANDROID_API_M__,
+ "Text-Relocations-Enforced-for-API-level-23",
+ "\"%s\" has text relocations",
+ get_realpath());
add_dlwarning(get_realpath(), "text relocations");
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
- DL_ERR("can't unprotect loadable segments for \"%s\": %s",
- get_realpath(), strerror(errno));
+ DL_ERR("can't unprotect loadable segments for \"%s\": %s", get_realpath(), strerror(errno));
return false;
}
}
@@ -3739,7 +3761,7 @@
&config,
&error_msg)) {
if (!error_msg.empty()) {
- DL_WARN("error reading config file \"%s\" for \"%s\" (will use default configuration): %s",
+ DL_WARN("Warning: couldn't read \"%s\" for \"%s\" (using default configuration instead): %s",
config_file,
executable_path,
error_msg.c_str());
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index 83c2f36..c00b734 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -194,14 +194,14 @@
std::string section_name;
- while(true) {
+ while (true) {
std::string name;
std::string value;
std::string error;
int result = cp.next_token(&name, &value, &error);
if (result == ConfigParser::kError) {
- DL_WARN("error parsing %s:%zd: %s (ignoring this line)",
+ DL_WARN("%s:%zd: warning: couldn't parse %s (ignoring this line)",
ld_config_file_path,
cp.lineno(),
error.c_str());
@@ -214,7 +214,7 @@
if (result == ConfigParser::kPropertyAssign) {
if (!android::base::StartsWith(name, "dir.")) {
- DL_WARN("error parsing %s:%zd: unexpected property name \"%s\", "
+ DL_WARN("%s:%zd: warning: unexpected property name \"%s\", "
"expected format dir.<section_name> (ignoring this line)",
ld_config_file_path,
cp.lineno(),
@@ -228,7 +228,7 @@
}
if (value.empty()) {
- DL_WARN("error parsing %s:%zd: property value is empty (ignoring this line)",
+ DL_WARN("%s:%zd: warning: property value is empty (ignoring this line)",
ld_config_file_path,
cp.lineno());
continue;
@@ -275,7 +275,7 @@
if (result == ConfigParser::kPropertyAssign) {
if (properties->find(name) != properties->end()) {
- DL_WARN("%s:%zd: warning: property \"%s\" redefinition",
+ DL_WARN("%s:%zd: warning: redefining property \"%s\" (overriding previous value)",
ld_config_file_path,
cp.lineno(),
name.c_str());
@@ -284,7 +284,7 @@
(*properties)[name] = PropertyValue(std::move(value), cp.lineno());
} else if (result == ConfigParser::kPropertyAppend) {
if (properties->find(name) == properties->end()) {
- DL_WARN("%s:%zd: warning: appending to property \"%s\" which isn't defined",
+ DL_WARN("%s:%zd: warning: appending to undefined property \"%s\" (treating as assignment)",
ld_config_file_path,
cp.lineno(),
name.c_str());
@@ -299,7 +299,7 @@
value = ":" + value;
(*properties)[name].append_value(std::move(value));
} else {
- DL_WARN("%s:%zd: warning: += isn't allowed to property \"%s\". Ignoring.",
+ DL_WARN("%s:%zd: warning: += isn't allowed for property \"%s\" (ignoring)",
ld_config_file_path,
cp.lineno(),
name.c_str());
@@ -308,7 +308,7 @@
}
if (result == ConfigParser::kError) {
- DL_WARN("error parsing %s:%zd: %s (ignoring this line)",
+ DL_WARN("%s:%zd: warning: couldn't parse %s (ignoring this line)",
ld_config_file_path,
cp.lineno(),
error.c_str());
diff --git a/linker/linker_globals.cpp b/linker/linker_globals.cpp
index 155ebf4..bcc2a1e 100644
--- a/linker/linker_globals.cpp
+++ b/linker/linker_globals.cpp
@@ -26,10 +26,12 @@
* SUCH DAMAGE.
*/
-
+#include "linker.h"
#include "linker_globals.h"
#include "linker_namespaces.h"
+#include "android-base/stringprintf.h"
+
int g_argc = 0;
char** g_argv = nullptr;
char** g_envp = nullptr;
@@ -48,3 +50,18 @@
return sizeof(__linker_dl_err_buf);
}
+void DL_WARN_documented_change(int api_level, const char* doc_link, const char* fmt, ...) {
+ std::string result{"Warning: "};
+
+ va_list ap;
+ va_start(ap, fmt);
+ android::base::StringAppendV(&result, fmt, ap);
+ va_end(ap);
+
+ android::base::StringAppendF(&result,
+ " and will not work when the app moves to API level %d or later "
+ "(https://android.googlesource.com/platform/bionic/+/master/%s) "
+ "(allowing for now because this app's target API level is still %d)",
+ api_level, doc_link, get_application_target_sdk_version());
+ DL_WARN("%s", result.c_str());
+}
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index b470918..32aa09d 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -49,6 +49,8 @@
async_safe_format_fd(2, "\n"); \
} while (false)
+void DL_WARN_documented_change(int api_level, const char* doc_link, const char* fmt, ...);
+
#define DL_ERR_AND_LOG(fmt, x...) \
do { \
DL_ERR(fmt, x); \
diff --git a/linker/linker_namespaces.cpp b/linker/linker_namespaces.cpp
index 9fdf0b5..fd72cdc 100644
--- a/linker/linker_namespaces.cpp
+++ b/linker/linker_namespaces.cpp
@@ -64,7 +64,8 @@
// This is workaround for apps hacking into soinfo list.
// and inserting their own entries into it. (http://b/37191433)
if (!si->has_min_version(3)) {
- DL_WARN("invalid soinfo version for \"%s\"", si->get_soname());
+ DL_WARN("Warning: invalid soinfo version for \"%s\" (assuming inaccessible)",
+ si->get_soname());
return false;
}
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index a9873c4..a5eab44 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -268,8 +268,10 @@
name_.c_str(), header_.e_shentsize, sizeof(ElfW(Shdr)));
return false;
}
- DL_WARN("\"%s\" has unsupported e_shentsize: 0x%x (expected 0x%zx)",
- name_.c_str(), header_.e_shentsize, sizeof(ElfW(Shdr)));
+ DL_WARN_documented_change(__ANDROID_API_O__,
+ "invalid-elf-header_section-headers-enforced-for-api-level-26",
+ "\"%s\" has unsupported e_shentsize 0x%x (expected 0x%zx)",
+ name_.c_str(), header_.e_shentsize, sizeof(ElfW(Shdr)));
add_dlwarning(name_.c_str(), "has invalid ELF header");
}
@@ -280,7 +282,9 @@
return false;
}
- DL_WARN("\"%s\" has invalid e_shstrndx", name_.c_str());
+ DL_WARN_documented_change(__ANDROID_API_O__,
+ "invalid-elf-header_section-headers-enforced-for-api-level-26",
+ "\"%s\" has invalid e_shstrndx", name_.c_str());
add_dlwarning(name_.c_str(), "has invalid ELF header");
}
@@ -395,11 +399,13 @@
pt_dynamic_offset);
return false;
}
- DL_WARN("\"%s\" .dynamic section has invalid offset: 0x%zx, "
- "expected to match PT_DYNAMIC offset: 0x%zx",
- name_.c_str(),
- static_cast<size_t>(dynamic_shdr->sh_offset),
- pt_dynamic_offset);
+ DL_WARN_documented_change(__ANDROID_API_O__,
+ "invalid-elf-header_section-headers-enforced-for-api-level-26",
+ "\"%s\" .dynamic section has invalid offset: 0x%zx "
+ "(expected to match PT_DYNAMIC offset 0x%zx)",
+ name_.c_str(),
+ static_cast<size_t>(dynamic_shdr->sh_offset),
+ pt_dynamic_offset);
add_dlwarning(name_.c_str(), "invalid .dynamic section");
}
@@ -412,11 +418,13 @@
pt_dynamic_filesz);
return false;
}
- DL_WARN("\"%s\" .dynamic section has invalid size: 0x%zx, "
- "expected to match PT_DYNAMIC filesz: 0x%zx",
- name_.c_str(),
- static_cast<size_t>(dynamic_shdr->sh_size),
- pt_dynamic_filesz);
+ DL_WARN_documented_change(__ANDROID_API_O__,
+ "invalid-elf-header_section-headers-enforced-for-api-level-26",
+ "\"%s\" .dynamic section has invalid size: 0x%zx "
+ "(expected to match PT_DYNAMIC filesz 0x%zx)",
+ name_.c_str(),
+ static_cast<size_t>(dynamic_shdr->sh_size),
+ pt_dynamic_filesz);
add_dlwarning(name_.c_str(), "invalid .dynamic section");
}
@@ -651,10 +659,13 @@
if ((prot & (PROT_EXEC | PROT_WRITE)) == (PROT_EXEC | PROT_WRITE)) {
// W + E PT_LOAD segments are not allowed in O.
if (get_application_target_sdk_version() >= __ANDROID_API_O__) {
- DL_ERR_AND_LOG("\"%s\": W + E load segments are not allowed", name_.c_str());
+ DL_ERR_AND_LOG("\"%s\": W+E load segments are not allowed", name_.c_str());
return false;
}
- DL_WARN("\"%s\": W + E load segments are not allowed", name_.c_str());
+ DL_WARN_documented_change(__ANDROID_API_O__,
+ "writable-and-executable-segments-enforced-for-api-level-26",
+ "\"%s\" has load segments that are both writable and executable",
+ name_.c_str());
add_dlwarning(name_.c_str(), "W+E load segments");
}
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 54bfcf0..731e8f5 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -152,7 +152,7 @@
ELF_ST_BIND(s->st_info) == STB_WEAK) {
return s->st_shndx != SHN_UNDEF;
} else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
- DL_WARN("unexpected ST_BIND value: %d for \"%s\" in \"%s\"",
+ DL_WARN("Warning: unexpected ST_BIND value: %d for \"%s\" in \"%s\" (ignoring)",
ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
}
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index 5bf88e7..661e7cb 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -209,31 +209,28 @@
const char* original_path = path.c_str();
if (realpath(original_path, resolved_path) != nullptr) {
struct stat s;
- if (stat(resolved_path, &s) == 0) {
- if (S_ISDIR(s.st_mode)) {
- resolved_paths->push_back(resolved_path);
- } else {
- DL_WARN("Warning: \"%s\" is not a directory (excluding from path)", resolved_path);
- continue;
- }
- } else {
- DL_WARN("Warning: cannot stat file \"%s\": %s", resolved_path, strerror(errno));
+ if (stat(resolved_path, &s) == -1) {
+ DL_WARN("Warning: cannot stat file \"%s\": %s (ignoring)", resolved_path, strerror(errno));
continue;
}
+ if (!S_ISDIR(s.st_mode)) {
+ DL_WARN("Warning: \"%s\" is not a directory (ignoring)", resolved_path);
+ continue;
+ }
+ resolved_paths->push_back(resolved_path);
} else {
+ std::string normalized_path;
+ if (!normalize_path(original_path, &normalized_path)) {
+ DL_WARN("Warning: unable to normalize \"%s\" (ignoring)", original_path);
+ continue;
+ }
+
std::string zip_path;
std::string entry_path;
-
- std::string normalized_path;
-
- if (!normalize_path(original_path, &normalized_path)) {
- DL_WARN("Warning: unable to normalize \"%s\"", original_path);
- continue;
- }
-
if (parse_zip_path(normalized_path.c_str(), &zip_path, &entry_path)) {
if (realpath(zip_path.c_str(), resolved_path) == nullptr) {
- DL_WARN("Warning: unable to resolve \"%s\": %s", zip_path.c_str(), strerror(errno));
+ DL_WARN("Warning: unable to resolve \"%s\": %s (ignoring)",
+ zip_path.c_str(), strerror(errno));
continue;
}
@@ -242,4 +239,3 @@
}
}
}
-
diff --git a/tests/Android.bp b/tests/Android.bp
index ec90296..66d5580 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -48,6 +48,18 @@
// All standard tests.
// -----------------------------------------------------------------------------
+// Test diagnostics emitted by clang. The library that results is useless; we
+// just want to run '-Xclang -verify', which will fail if the diagnostics don't
+// match up with what the source file says they should be.
+cc_test_library {
+ name: "clang_diagnostic_tests",
+ cflags: [
+ "-Xclang",
+ "-verify",
+ ],
+ srcs: ["sys_ioctl_diag_test.cpp"],
+}
+
cc_test_library {
name: "libBionicStandardTests",
defaults: ["bionic_tests_defaults"],
@@ -486,8 +498,10 @@
"libdl_preempt_test_1",
"libdl_preempt_test_2",
"libdl_test_df_1_global",
+ "libelf-tls-library",
"libgnu-hash-table-library",
"libsysv-hash-table-library",
+ "libtestshared",
"libtest_atexit",
"libtest_check_order_dlsym_1_left",
"libtest_check_order_dlsym_2_right",
@@ -512,6 +526,7 @@
"libtest_check_order_reloc_siblings_f",
"libtest_check_order_reloc_siblings",
"libtest_check_rtld_next_from_library",
+ "libtest_dlopen_df_1_global",
"libtest_dlopen_from_ctor_main",
"libtest_dlopen_from_ctor",
"libtest_dlopen_weak_undefined_func",
@@ -522,11 +537,15 @@
"libtest_dlsym_weak_func",
"libtest_dt_runpath_d",
"libtest_empty",
+ "libtest_ifunc_variable_impl",
+ "libtest_ifunc_variable",
"libtest_ifunc",
"libtest_init_fini_order_child",
"libtest_init_fini_order_grand_child",
"libtest_init_fini_order_root2",
"libtest_init_fini_order_root",
+ "libtest_missing_symbol_root",
+ "libtest_missing_symbol",
"libtest_nodelete_1",
"libtest_nodelete_2",
"libtest_nodelete_dt_flags_1",
@@ -561,6 +580,7 @@
"libtest_invalid-zero_shstrndx.so",
"libtest_invalid-textrels.so",
"libtest_invalid-textrels2.so",
+ "libtest_thread_local_dtor",
"preinit_getauxval_test_helper",
"preinit_syscall_test_helper",
"libnstest_private_external",
diff --git a/tests/ScopedSignalHandler.h b/tests/ScopedSignalHandler.h
deleted file mode 100644
index 36bbf10..0000000
--- a/tests/ScopedSignalHandler.h
+++ /dev/null
@@ -1,91 +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.
- */
-
-#ifndef _BIONIC_TESTS_SCOPED_SIGNAL_HANDLER_H
-#define _BIONIC_TESTS_SCOPED_SIGNAL_HANDLER_H
-
-#include <signal.h>
-#include <string.h>
-
-#if defined(__GLIBC__)
-#define posix_spawnattr_getsigdefault64 posix_spawnattr_getsigdefault
-#define posix_spawnattr_getsigmask64 posix_spawnattr_getsigmask
-#define posix_spawnattr_setsigdefault64 posix_spawnattr_setsigdefault
-#define posix_spawnattr_setsigmask64 posix_spawnattr_setsigmask
-#define pthread_sigmask64 pthread_sigmask
-#define sigaction64 sigaction
-#define sigaddset64 sigaddset
-#define sigdelset64 sigdelset
-#define sigemptyset64 sigemptyset
-#define sigfillset64 sigfillset
-#define sigismember64 sigismember
-#define sigpending64 sigpending
-#define sigprocmask64 sigprocmask
-#define sigset64_t sigset_t
-#define sigsuspend64 sigsuspend
-#define sigtimedwait64 sigtimedwait
-#define sigwait64 sigwait
-#define sigwaitinfo64 sigwaitinfo
-#endif
-
-class ScopedSignalHandler {
- public:
- ScopedSignalHandler(int signal_number, void (*handler)(int), int sa_flags = 0)
- : signal_number_(signal_number) {
- memset(&action_, 0, sizeof(action_));
- action_.sa_flags = sa_flags;
- action_.sa_handler = handler;
- sigaction64(signal_number_, &action_, &old_action_);
- }
-
- ScopedSignalHandler(int signal_number, void (*action)(int, siginfo_t*, void*),
- int sa_flags = SA_SIGINFO)
- : signal_number_(signal_number) {
- memset(&action_, 0, sizeof(action_));
- action_.sa_flags = sa_flags;
- action_.sa_sigaction = action;
- sigaction64(signal_number_, &action_, &old_action_);
- }
-
- ScopedSignalHandler(int signal_number) : signal_number_(signal_number) {
- sigaction64(signal_number, nullptr, &old_action_);
- }
-
- ~ScopedSignalHandler() {
- sigaction64(signal_number_, &old_action_, NULL);
- }
-
- private:
- struct sigaction64 action_;
- struct sigaction64 old_action_;
- const int signal_number_;
-};
-
-class SignalMaskRestorer {
- public:
- SignalMaskRestorer() {
- sigprocmask64(SIG_SETMASK, nullptr, &old_mask_);
- }
-
- ~SignalMaskRestorer() {
- sigprocmask64(SIG_SETMASK, &old_mask_, nullptr);
- }
-
- private:
- sigset64_t old_mask_;
-};
-
-#endif // _BIONIC_TESTS_SCOPED_SIGNAL_HANDLER_H
diff --git a/tests/SignalUtils.h b/tests/SignalUtils.h
new file mode 100644
index 0000000..ece28ba
--- /dev/null
+++ b/tests/SignalUtils.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <signal.h>
+#include <string.h>
+
+#if defined(__GLIBC__)
+#define posix_spawnattr_getsigdefault64 posix_spawnattr_getsigdefault
+#define posix_spawnattr_getsigmask64 posix_spawnattr_getsigmask
+#define posix_spawnattr_setsigdefault64 posix_spawnattr_setsigdefault
+#define posix_spawnattr_setsigmask64 posix_spawnattr_setsigmask
+#define pthread_sigmask64 pthread_sigmask
+#define sigaction64 sigaction
+#define sigaddset64 sigaddset
+#define sigdelset64 sigdelset
+#define sigemptyset64 sigemptyset
+#define sigfillset64 sigfillset
+#define sigismember64 sigismember
+#define sigpending64 sigpending
+#define sigprocmask64 sigprocmask
+#define sigset64_t sigset_t
+#define sigsuspend64 sigsuspend
+#define sigtimedwait64 sigtimedwait
+#define sigwait64 sigwait
+#define sigwaitinfo64 sigwaitinfo
+#endif
+
+#include "private/ScopedSignalHandler.h"
+
+class SignalMaskRestorer {
+ public:
+ SignalMaskRestorer() {
+ sigprocmask64(SIG_SETMASK, nullptr, &old_mask_);
+ }
+
+ ~SignalMaskRestorer() {
+ sigprocmask64(SIG_SETMASK, &old_mask_, nullptr);
+ }
+
+ private:
+ sigset64_t old_mask_;
+};
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index c40a35b..84f525d 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1080,6 +1080,13 @@
ASSERT_SUBSTR("libsysv-hash-table-library.so", dlinfo.dli_fname);
}
+TEST(dlfcn, dlopen_library_with_ELF_TLS) {
+ dlerror(); // Clear any pending errors.
+ void* handle = dlopen("libelf-tls-library.so", RTLD_NOW);
+ ASSERT_TRUE(handle == nullptr);
+ ASSERT_SUBSTR("unsupported ELF TLS", dlerror());
+}
+
TEST(dlfcn, dlopen_bad_flags) {
dlerror(); // Clear any pending errors.
void* handle;
@@ -1503,7 +1510,7 @@
"/libtest_invalid-rw_load_segment.so";
void* handle = dlopen(libpath.c_str(), RTLD_NOW);
ASSERT_TRUE(handle == nullptr);
- std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W + E load segments are not allowed";
+ std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W+E load segments are not allowed";
ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
}
diff --git a/tests/fenv_test.cpp b/tests/fenv_test.cpp
index 9fc7d96..d27808f 100644
--- a/tests/fenv_test.cpp
+++ b/tests/fenv_test.cpp
@@ -16,7 +16,6 @@
#include <gtest/gtest.h>
-#include "ScopedSignalHandler.h"
#include "utils.h"
#include <fenv.h>
diff --git a/tests/fortify_filecheck_diagnostics_test.cpp b/tests/fortify_filecheck_diagnostics_test.cpp
index c6198c6..375a156 100644
--- a/tests/fortify_filecheck_diagnostics_test.cpp
+++ b/tests/fortify_filecheck_diagnostics_test.cpp
@@ -278,7 +278,15 @@
// NOLINTNEXTLINE(whitespace/line_length)
// GCC: error: call to '__ppoll_too_small_error' declared with attribute error: ppoll: pollfd array smaller than fd count
// CLANG: error: in call to 'ppoll', fd_count is larger than the given buffer
- ppoll(fds, 2, &timeout, NULL);
+ ppoll(fds, 2, &timeout, nullptr);
+}
+
+void test_ppoll64() {
+ pollfd fds[1];
+ timespec timeout;
+ // NOLINTNEXTLINE(whitespace/line_length)
+ // CLANG: error: in call to 'ppoll64', fd_count is larger than the given buffer
+ ppoll64(fds, 2, &timeout, nullptr);
}
void test_fread_overflow() {
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index 67c124d..bc33251 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -417,11 +417,9 @@
ASSERT_FORTIFY(sprintf(buf, "%s", source_buf));
}
-#ifdef __clang__ && !__has_attribute(alloc_size)
+#if !__has_attribute(alloc_size)
// TODO: remove this after Clang prebuilt rebase.
#else
-// This test is disabled in clang because clang doesn't properly detect
-// this buffer overflow. TODO: Fix clang.
TEST_F(DEATHTEST, sprintf_malloc_fortified) {
char* buf = (char *) malloc(10);
char source_buf[11];
@@ -995,7 +993,18 @@
// Set timeout to zero to prevent waiting in ppoll when fortify test fails.
timespec timeout;
timeout.tv_sec = timeout.tv_nsec = 0;
- ASSERT_FORTIFY(ppoll(buf, fd_count, &timeout, NULL));
+ ASSERT_FORTIFY(ppoll(buf, fd_count, &timeout, nullptr));
+}
+
+TEST_F(DEATHTEST, ppoll64_fortified) {
+#if __BIONIC__ // glibc doesn't have ppoll64.
+ nfds_t fd_count = atoi("2"); // suppress compiler optimizations
+ pollfd buf[1] = {{0, POLLIN, 0}};
+ // Set timeout to zero to prevent waiting in ppoll when fortify test fails.
+ timespec timeout;
+ timeout.tv_sec = timeout.tv_nsec = 0;
+ ASSERT_FORTIFY(ppoll64(buf, fd_count, &timeout, nullptr));
+#endif
}
TEST_F(DEATHTEST, open_O_CREAT_without_mode_fortified) {
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index a905fae..12d4b7f 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -115,10 +115,14 @@
#else // !defined(__BIONIC__)
-static void check_get_passwd(const char* /* username */, uid_t /* uid */, uid_type_t /* uid_type */) {
+static void print_no_getpwnam_test_info() {
GTEST_LOG_(INFO) << "This test is about uid/username translation for Android, which does nothing on libc other than bionic.\n";
}
+static void check_get_passwd(const char* /* username */, uid_t /* uid */, uid_type_t /* uid_type */) {
+ print_no_getpwnam_test_info();
+}
+
#endif
TEST(pwd, getpwnam_system_id_root) {
@@ -238,6 +242,7 @@
}
TEST(pwd, getpwent_iterate) {
+#if defined(__BIONIC__)
passwd* pwd;
std::set<uid_t> uids;
@@ -263,6 +268,9 @@
endpwent();
expect_ids(uids);
+#else
+ print_no_getpwnam_test_info();
+#endif
}
static void check_group(const group* grp, const char* group_name, gid_t gid) {
@@ -477,6 +485,7 @@
}
TEST(grp, getgrent_iterate) {
+#if defined(__BIONIC__)
group* grp;
std::set<gid_t> gids;
@@ -493,4 +502,7 @@
endgrent();
expect_ids(gids);
+#else
+ print_no_getgrnam_test_info();
+#endif
}
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 6b20094..6f8c403 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -317,6 +317,12 @@
line.pop_back();
testcase_list.push_back(TestCase(line.c_str()));
} else {
+ if (testcase_list.empty()) {
+ // Invalid response from gtest - likely it has been upset by an invalid --gtest_* flag.
+ // Relay the message to user.
+ fprintf(stderr, "%s", content.c_str());
+ return false;
+ }
testcase_list.back().AppendTest(line.c_str());
}
}
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 3afda67..ae5f78a 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -40,6 +40,16 @@
}
// -----------------------------------------------------------------------------
+// Library to test ELF TLS
+// -----------------------------------------------------------------------------
+cc_test_library {
+ name: "libelf-tls-library",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["elf_tls_test_library.cpp"],
+ cflags: ["-fno-emulated-tls"],
+}
+
+// -----------------------------------------------------------------------------
// Library to test gnu-styled hash
// -----------------------------------------------------------------------------
cc_test_library {
diff --git a/tests/libs/elf_tls_test_library.cpp b/tests/libs/elf_tls_test_library.cpp
new file mode 100644
index 0000000..56d0171
--- /dev/null
+++ b/tests/libs/elf_tls_test_library.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+thread_local int elf_tls_variable;
+
+extern "C" int* get() { return &elf_tls_variable; }
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index dd7879c..af682a9 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -40,7 +40,7 @@
#include "private/bionic_constants.h"
#include "private/bionic_macros.h"
#include "BionicDeathTest.h"
-#include "ScopedSignalHandler.h"
+#include "SignalUtils.h"
#include "utils.h"
TEST(pthread, pthread_key_create) {
@@ -893,6 +893,7 @@
std::function<int (pthread_rwlock_t*)> trylock_function;
std::function<int (pthread_rwlock_t*)> lock_function;
std::function<int (pthread_rwlock_t*, const timespec*)> timed_lock_function;
+ clockid_t clock;
};
static void pthread_rwlock_wakeup_helper(RwlockWakeupHelperArg* arg) {
@@ -944,6 +945,19 @@
});
}
+TEST(pthread, pthread_rwlock_reader_wakeup_writer_timedwait_monotonic_np) {
+#if defined(__BIONIC__)
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+ ts.tv_sec += 1;
+ test_pthread_rwlock_reader_wakeup_writer(
+ [&](pthread_rwlock_t* lock) { return pthread_rwlock_timedwrlock_monotonic_np(lock, &ts); });
+#else // __BIONIC__
+ GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedwrlock_monotonic_np is "
+ "only supported on bionic";
+#endif // __BIONIC__
+}
+
static void test_pthread_rwlock_writer_wakeup_reader(std::function<int (pthread_rwlock_t*)> lock_function) {
RwlockWakeupHelperArg wakeup_arg;
ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, NULL));
@@ -980,6 +994,19 @@
});
}
+TEST(pthread, pthread_rwlock_writer_wakeup_reader_timedwait_monotonic_np) {
+#if defined(__BIONIC__)
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+ ts.tv_sec += 1;
+ test_pthread_rwlock_writer_wakeup_reader(
+ [&](pthread_rwlock_t* lock) { return pthread_rwlock_timedrdlock_monotonic_np(lock, &ts); });
+#else // __BIONIC__
+ GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedrdlock_monotonic_np is "
+ "only supported on bionic";
+#endif // __BIONIC__
+}
+
static void pthread_rwlock_wakeup_timeout_helper(RwlockWakeupHelperArg* arg) {
arg->tid = gettid();
ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
@@ -988,7 +1015,7 @@
ASSERT_EQ(EBUSY, arg->trylock_function(&arg->lock));
timespec ts;
- ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+ ASSERT_EQ(0, clock_gettime(arg->clock, &ts));
ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
ts.tv_nsec = -1;
ASSERT_EQ(EINVAL, arg->timed_lock_function(&arg->lock, &ts));
@@ -997,21 +1024,60 @@
ts.tv_nsec = NS_PER_S - 1;
ts.tv_sec = -1;
ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
- ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+ ASSERT_EQ(0, clock_gettime(arg->clock, &ts));
ts.tv_sec += 1;
ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, arg->progress);
arg->progress = RwlockWakeupHelperArg::LOCK_TIMEDOUT;
}
-TEST(pthread, pthread_rwlock_timedrdlock_timeout) {
+static void pthread_rwlock_timedrdlock_timeout_helper(
+ clockid_t clock, int (*lock_function)(pthread_rwlock_t* __rwlock, const timespec* __timeout)) {
RwlockWakeupHelperArg wakeup_arg;
ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
ASSERT_EQ(0, pthread_rwlock_wrlock(&wakeup_arg.lock));
wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
wakeup_arg.tid = 0;
wakeup_arg.trylock_function = &pthread_rwlock_tryrdlock;
- wakeup_arg.timed_lock_function = &pthread_rwlock_timedrdlock;
+ wakeup_arg.timed_lock_function = lock_function;
+ wakeup_arg.clock = clock;
+
+ pthread_t thread;
+ ASSERT_EQ(0, pthread_create(&thread, nullptr,
+ reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_timeout_helper), &wakeup_arg));
+ WaitUntilThreadSleep(wakeup_arg.tid);
+ ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
+
+ ASSERT_EQ(0, pthread_join(thread, nullptr));
+ ASSERT_EQ(RwlockWakeupHelperArg::LOCK_TIMEDOUT, wakeup_arg.progress);
+ ASSERT_EQ(0, pthread_rwlock_unlock(&wakeup_arg.lock));
+ ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
+}
+
+TEST(pthread, pthread_rwlock_timedrdlock_timeout) {
+ pthread_rwlock_timedrdlock_timeout_helper(CLOCK_REALTIME, pthread_rwlock_timedrdlock);
+}
+
+TEST(pthread, pthread_rwlock_timedrdlock_monotonic_np_timeout) {
+#if defined(__BIONIC__)
+ pthread_rwlock_timedrdlock_timeout_helper(CLOCK_MONOTONIC,
+ pthread_rwlock_timedrdlock_monotonic_np);
+#else // __BIONIC__
+ GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedrdlock_monotonic_np is "
+ "only supported on bionic";
+#endif // __BIONIC__
+}
+
+static void pthread_rwlock_timedwrlock_timeout_helper(
+ clockid_t clock, int (*lock_function)(pthread_rwlock_t* __rwlock, const timespec* __timeout)) {
+ RwlockWakeupHelperArg wakeup_arg;
+ ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
+ ASSERT_EQ(0, pthread_rwlock_rdlock(&wakeup_arg.lock));
+ wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
+ wakeup_arg.tid = 0;
+ wakeup_arg.trylock_function = &pthread_rwlock_trywrlock;
+ wakeup_arg.timed_lock_function = lock_function;
+ wakeup_arg.clock = clock;
pthread_t thread;
ASSERT_EQ(0, pthread_create(&thread, nullptr,
@@ -1026,24 +1092,17 @@
}
TEST(pthread, pthread_rwlock_timedwrlock_timeout) {
- RwlockWakeupHelperArg wakeup_arg;
- ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
- ASSERT_EQ(0, pthread_rwlock_rdlock(&wakeup_arg.lock));
- wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
- wakeup_arg.tid = 0;
- wakeup_arg.trylock_function = &pthread_rwlock_trywrlock;
- wakeup_arg.timed_lock_function = &pthread_rwlock_timedwrlock;
+ pthread_rwlock_timedwrlock_timeout_helper(CLOCK_REALTIME, pthread_rwlock_timedwrlock);
+}
- pthread_t thread;
- ASSERT_EQ(0, pthread_create(&thread, nullptr,
- reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_timeout_helper), &wakeup_arg));
- WaitUntilThreadSleep(wakeup_arg.tid);
- ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
-
- ASSERT_EQ(0, pthread_join(thread, nullptr));
- ASSERT_EQ(RwlockWakeupHelperArg::LOCK_TIMEDOUT, wakeup_arg.progress);
- ASSERT_EQ(0, pthread_rwlock_unlock(&wakeup_arg.lock));
- ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
+TEST(pthread, pthread_rwlock_timedwrlock_monotonic_np_timeout) {
+#if defined(__BIONIC__)
+ pthread_rwlock_timedwrlock_timeout_helper(CLOCK_MONOTONIC,
+ pthread_rwlock_timedwrlock_monotonic_np);
+#else // __BIONIC__
+ GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedwrlock_monotonic_np is "
+ "only supported on bionic";
+#endif // __BIONIC__
}
class RwlockKindTestHelper {
@@ -1376,25 +1435,59 @@
ASSERT_EQ(0, pthread_cond_signal(&cond));
}
-TEST(pthread, pthread_cond_timedwait_timeout) {
+TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_MONOTONIC_np) {
+#if defined(__BIONIC__)
+ InitCond(CLOCK_REALTIME);
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+ ts.tv_sec += 1;
+ StartWaitingThread([&](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+ return pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
+ });
+ progress = SIGNALED;
+ ASSERT_EQ(0, pthread_cond_signal(&cond));
+#else // __BIONIC__
+ GTEST_LOG_(INFO) << "This test does nothing since pthread_cond_timedwait_monotonic_np is only "
+ "supported on bionic";
+#endif // __BIONIC__
+}
+
+static void pthread_cond_timedwait_timeout_helper(clockid_t clock,
+ int (*wait_function)(pthread_cond_t* __cond,
+ pthread_mutex_t* __mutex,
+ const timespec* __timeout)) {
pthread_mutex_t mutex;
ASSERT_EQ(0, pthread_mutex_init(&mutex, nullptr));
pthread_cond_t cond;
ASSERT_EQ(0, pthread_cond_init(&cond, nullptr));
ASSERT_EQ(0, pthread_mutex_lock(&mutex));
+
timespec ts;
- ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
- ASSERT_EQ(ETIMEDOUT, pthread_cond_timedwait(&cond, &mutex, &ts));
+ ASSERT_EQ(0, clock_gettime(clock, &ts));
+ ASSERT_EQ(ETIMEDOUT, wait_function(&cond, &mutex, &ts));
ts.tv_nsec = -1;
- ASSERT_EQ(EINVAL, pthread_cond_timedwait(&cond, &mutex, &ts));
+ ASSERT_EQ(EINVAL, wait_function(&cond, &mutex, &ts));
ts.tv_nsec = NS_PER_S;
- ASSERT_EQ(EINVAL, pthread_cond_timedwait(&cond, &mutex, &ts));
+ ASSERT_EQ(EINVAL, wait_function(&cond, &mutex, &ts));
ts.tv_nsec = NS_PER_S - 1;
ts.tv_sec = -1;
- ASSERT_EQ(ETIMEDOUT, pthread_cond_timedwait(&cond, &mutex, &ts));
+ ASSERT_EQ(ETIMEDOUT, wait_function(&cond, &mutex, &ts));
ASSERT_EQ(0, pthread_mutex_unlock(&mutex));
}
+TEST(pthread, pthread_cond_timedwait_timeout) {
+ pthread_cond_timedwait_timeout_helper(CLOCK_REALTIME, pthread_cond_timedwait);
+}
+
+TEST(pthread, pthread_cond_timedwait_monotonic_np_timeout) {
+#if defined(__BIONIC__)
+ pthread_cond_timedwait_timeout_helper(CLOCK_MONOTONIC, pthread_cond_timedwait_monotonic_np);
+#else // __BIONIC__
+ GTEST_LOG_(INFO) << "This test does nothing since pthread_cond_timedwait_monotonic_np is only "
+ "supported on bionic";
+#endif // __BIONIC__
+}
+
TEST(pthread, pthread_attr_getstack__main_thread) {
// This test is only meaningful for the main thread, so make sure we're running on it!
ASSERT_EQ(getpid(), syscall(__NR_gettid));
@@ -1718,7 +1811,6 @@
void destroy() {
ASSERT_EQ(0, pthread_mutex_destroy(&lock));
- ASSERT_EQ(EBUSY, pthread_mutex_destroy(&lock));
}
DISALLOW_COPY_AND_ASSIGN(PthreadMutex);
@@ -2000,7 +2092,9 @@
#endif
}
-TEST(pthread, pthread_mutex_timedlock) {
+static void pthread_mutex_timedlock_helper(clockid_t clock,
+ int (*lock_function)(pthread_mutex_t* __mutex,
+ const timespec* __timeout)) {
pthread_mutex_t m;
ASSERT_EQ(0, pthread_mutex_init(&m, nullptr));
@@ -2008,51 +2102,115 @@
ASSERT_EQ(0, pthread_mutex_lock(&m));
timespec ts;
- ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
- ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+ ASSERT_EQ(0, clock_gettime(clock, &ts));
+ ASSERT_EQ(ETIMEDOUT, lock_function(&m, &ts));
ts.tv_nsec = -1;
- ASSERT_EQ(EINVAL, pthread_mutex_timedlock(&m, &ts));
+ ASSERT_EQ(EINVAL, lock_function(&m, &ts));
ts.tv_nsec = NS_PER_S;
- ASSERT_EQ(EINVAL, pthread_mutex_timedlock(&m, &ts));
+ ASSERT_EQ(EINVAL, lock_function(&m, &ts));
ts.tv_nsec = NS_PER_S - 1;
ts.tv_sec = -1;
- ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+ ASSERT_EQ(ETIMEDOUT, lock_function(&m, &ts));
// If the mutex is unlocked, pthread_mutex_timedlock should succeed.
ASSERT_EQ(0, pthread_mutex_unlock(&m));
- ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+ ASSERT_EQ(0, clock_gettime(clock, &ts));
ts.tv_sec += 1;
- ASSERT_EQ(0, pthread_mutex_timedlock(&m, &ts));
+ ASSERT_EQ(0, lock_function(&m, &ts));
ASSERT_EQ(0, pthread_mutex_unlock(&m));
ASSERT_EQ(0, pthread_mutex_destroy(&m));
}
-TEST(pthread, pthread_mutex_timedlock_pi) {
+TEST(pthread, pthread_mutex_timedlock) {
+ pthread_mutex_timedlock_helper(CLOCK_REALTIME, pthread_mutex_timedlock);
+}
+
+TEST(pthread, pthread_mutex_timedlock_monotonic_np) {
+#if defined(__BIONIC__)
+ pthread_mutex_timedlock_helper(CLOCK_MONOTONIC, pthread_mutex_timedlock_monotonic_np);
+#else // __BIONIC__
+ GTEST_LOG_(INFO) << "This test does nothing since pthread_mutex_timedlock_monotonic_np is only "
+ "supported on bionic";
+#endif // __BIONIC__
+}
+
+static void pthread_mutex_timedlock_pi_helper(clockid_t clock,
+ int (*lock_function)(pthread_mutex_t* __mutex,
+ const timespec* __timeout)) {
PthreadMutex m(PTHREAD_MUTEX_NORMAL, PTHREAD_PRIO_INHERIT);
+
timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
+ clock_gettime(clock, &ts);
ts.tv_sec += 1;
- ASSERT_EQ(0, pthread_mutex_timedlock(&m.lock, &ts));
+ ASSERT_EQ(0, lock_function(&m.lock, &ts));
+
+ struct ThreadArgs {
+ clockid_t clock;
+ int (*lock_function)(pthread_mutex_t* __mutex, const timespec* __timeout);
+ PthreadMutex& m;
+ };
+
+ ThreadArgs thread_args = {
+ .clock = clock,
+ .lock_function = lock_function,
+ .m = m,
+ };
auto ThreadFn = [](void* arg) -> void* {
- PthreadMutex& m = *static_cast<PthreadMutex*>(arg);
+ auto args = static_cast<ThreadArgs*>(arg);
timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
+ clock_gettime(args->clock, &ts);
ts.tv_sec += 1;
- intptr_t result = pthread_mutex_timedlock(&m.lock, &ts);
+ intptr_t result = args->lock_function(&args->m.lock, &ts);
return reinterpret_cast<void*>(result);
};
pthread_t thread;
- ASSERT_EQ(0, pthread_create(&thread, NULL, ThreadFn, &m));
+ ASSERT_EQ(0, pthread_create(&thread, NULL, ThreadFn, &thread_args));
void* result;
ASSERT_EQ(0, pthread_join(thread, &result));
ASSERT_EQ(ETIMEDOUT, reinterpret_cast<intptr_t>(result));
ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
}
+TEST(pthread, pthread_mutex_timedlock_pi) {
+ pthread_mutex_timedlock_pi_helper(CLOCK_REALTIME, pthread_mutex_timedlock);
+}
+
+TEST(pthread, pthread_mutex_timedlock_monotonic_np_pi) {
+#if defined(__BIONIC__)
+ pthread_mutex_timedlock_pi_helper(CLOCK_MONOTONIC, pthread_mutex_timedlock_monotonic_np);
+#else // __BIONIC__
+ GTEST_LOG_(INFO) << "This test does nothing since pthread_mutex_timedlock_monotonic_np is only "
+ "supported on bionic";
+#endif // __BIONIC__
+}
+
+TEST(pthread, pthread_mutex_using_destroyed_mutex) {
+#if defined(__BIONIC__)
+ pthread_mutex_t m;
+ ASSERT_EQ(0, pthread_mutex_init(&m, nullptr));
+ ASSERT_EQ(0, pthread_mutex_destroy(&m));
+ ASSERT_EXIT(pthread_mutex_lock(&m), ::testing::KilledBySignal(SIGABRT),
+ "pthread_mutex_lock called on a destroyed mutex");
+ ASSERT_EXIT(pthread_mutex_unlock(&m), ::testing::KilledBySignal(SIGABRT),
+ "pthread_mutex_unlock called on a destroyed mutex");
+ ASSERT_EXIT(pthread_mutex_trylock(&m), ::testing::KilledBySignal(SIGABRT),
+ "pthread_mutex_trylock called on a destroyed mutex");
+ timespec ts;
+ ASSERT_EXIT(pthread_mutex_timedlock(&m, &ts), ::testing::KilledBySignal(SIGABRT),
+ "pthread_mutex_timedlock called on a destroyed mutex");
+ ASSERT_EXIT(pthread_mutex_timedlock_monotonic_np(&m, &ts), ::testing::KilledBySignal(SIGABRT),
+ "pthread_mutex_timedlock_monotonic_np called on a destroyed mutex");
+ ASSERT_EXIT(pthread_mutex_destroy(&m), ::testing::KilledBySignal(SIGABRT),
+ "pthread_mutex_destroy called on a destroyed mutex");
+#else
+ GTEST_LOG_(INFO) << "This test tests bionic pthread mutex implementation details.";
+#endif
+}
+
class StrictAlignmentAllocator {
public:
void* allocate(size_t size, size_t alignment) {
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index 24a2dbe..607e37f 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -24,7 +24,7 @@
#include <unistd.h>
#include "private/bionic_constants.h"
-#include "ScopedSignalHandler.h"
+#include "SignalUtils.h"
TEST(semaphore, sem_init) {
sem_t s;
@@ -101,37 +101,51 @@
}
}
-TEST(semaphore, sem_timedwait) {
+static void sem_timedwait_helper(clockid_t clock,
+ int (*wait_function)(sem_t* __sem, const timespec* __ts)) {
sem_t s;
ASSERT_EQ(0, sem_init(&s, 0, 0));
timespec ts;
- ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+ ASSERT_EQ(0, clock_gettime(clock, &ts));
timespec_add_ms(ts, 100);
errno = 0;
- ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+ ASSERT_EQ(-1, wait_function(&s, &ts));
ASSERT_EQ(ETIMEDOUT, errno);
// A negative timeout is an error.
errno = 0;
ts.tv_nsec = -1;
- ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+ ASSERT_EQ(-1, wait_function(&s, &ts));
ASSERT_EQ(EINVAL, errno);
errno = 0;
ts.tv_nsec = NS_PER_S;
- ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+ ASSERT_EQ(-1, wait_function(&s, &ts));
ASSERT_EQ(EINVAL, errno);
errno = 0;
ts.tv_nsec = NS_PER_S - 1;
ts.tv_sec = -1;
- ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+ ASSERT_EQ(-1, wait_function(&s, &ts));
ASSERT_EQ(ETIMEDOUT, errno);
ASSERT_EQ(0, sem_destroy(&s));
}
+TEST(semaphore, sem_timedwait) {
+ sem_timedwait_helper(CLOCK_REALTIME, sem_timedwait);
+}
+
+TEST(semaphore, sem_timedwait_monotonic_np) {
+#if defined(__BIONIC__)
+ sem_timedwait_helper(CLOCK_MONOTONIC, sem_timedwait_monotonic_np);
+#else // __BIONIC__
+ GTEST_LOG_(INFO)
+ << "This test does nothing since sem_timedwait_monotonic_np is only supported on bionic";
+#endif // __BIONIC__
+}
+
TEST(semaphore_DeathTest, sem_timedwait_null_timeout) {
sem_t s;
ASSERT_EQ(0, sem_init(&s, 0, 0));
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index 4f5e60c..a49e910 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -19,7 +19,7 @@
#include <setjmp.h>
#include <stdlib.h>
-#include "ScopedSignalHandler.h"
+#include "SignalUtils.h"
TEST(setjmp, setjmp_smoke) {
int value;
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index d374c50..53c91a2 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -24,7 +24,7 @@
#include <gtest/gtest.h>
-#include "ScopedSignalHandler.h"
+#include "SignalUtils.h"
static int SIGNAL_MIN() {
return 1; // Signals start at 1 (SIGHUP), not 0.
@@ -337,6 +337,214 @@
TestSigAction(sigaction64, sigaddset64, SIGRTMIN);
}
+static void ClearSignalMask() {
+ uint64_t sigset = 0;
+ if (syscall(__NR_rt_sigprocmask, SIG_SETMASK, &sigset, nullptr, sizeof(sigset)) != 0) {
+ abort();
+ }
+}
+
+static uint64_t GetSignalMask() {
+ uint64_t sigset;
+ if (syscall(__NR_rt_sigprocmask, SIG_SETMASK, nullptr, &sigset, sizeof(sigset)) != 0) {
+ abort();
+ }
+ return sigset;
+}
+
+enum class SignalMaskFunctionType {
+ RtAware,
+ RtNonaware,
+};
+
+#if defined(__LP64__) || !defined(__BIONIC__)
+constexpr SignalMaskFunctionType sigset_type = SignalMaskFunctionType::RtAware;
+#else
+constexpr SignalMaskFunctionType sigset_type = SignalMaskFunctionType::RtNonaware;
+#endif
+
+static void TestSignalMaskFiltered(uint64_t sigset, SignalMaskFunctionType type) {
+ for (int signo = 1; signo <= 64; ++signo) {
+ bool signal_blocked = sigset & (1ULL << (signo - 1));
+ if (signo == SIGKILL || signo == SIGSTOP) {
+ // SIGKILL and SIGSTOP shouldn't be blocked.
+ EXPECT_EQ(false, signal_blocked) << "signal " << signo;
+ } else if (signo < __SIGRTMIN) {
+ // Everything else should be blocked.
+ EXPECT_EQ(true, signal_blocked) << "signal " << signo;
+ } else if (signo >= __SIGRTMIN && signo < SIGRTMIN) {
+ // Reserved signals must not be blocked.
+ EXPECT_EQ(false, signal_blocked) << "signal " << signo;
+ } else if (type == SignalMaskFunctionType::RtAware) {
+ // Realtime signals should be blocked, unless we blocked using a non-rt aware function.
+ EXPECT_EQ(true, signal_blocked) << "signal " << signo;
+ }
+ }
+}
+
+static void TestSignalMaskFunction(std::function<void()> fn, SignalMaskFunctionType fn_type) {
+ ClearSignalMask();
+ fn();
+ TestSignalMaskFiltered(GetSignalMask(), fn_type);
+}
+
+TEST(signal, sigaction_filter) {
+ ClearSignalMask();
+ static uint64_t sigset;
+ struct sigaction sa = {};
+ sa.sa_handler = [](int) { sigset = GetSignalMask(); };
+ sigfillset(&sa.sa_mask);
+ sigaction(SIGUSR1, &sa, nullptr);
+ raise(SIGUSR1);
+ ASSERT_NE(0ULL, sigset);
+ TestSignalMaskFiltered(sigset, sigset_type);
+}
+
+TEST(signal, sigaction64_filter) {
+ ClearSignalMask();
+ static uint64_t sigset;
+ struct sigaction64 sa = {};
+ sa.sa_handler = [](int) { sigset = GetSignalMask(); };
+ sigfillset64(&sa.sa_mask);
+ sigaction64(SIGUSR1, &sa, nullptr);
+ raise(SIGUSR1);
+ ASSERT_NE(0ULL, sigset);
+ TestSignalMaskFiltered(sigset, SignalMaskFunctionType::RtAware);
+}
+
+TEST(signal, sigprocmask_setmask_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset_t sigset_libc;
+ sigfillset(&sigset_libc);
+ ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &sigset_libc, nullptr));
+ },
+ sigset_type);
+}
+
+TEST(signal, sigprocmask64_setmask_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset64_t sigset_libc;
+ sigfillset64(&sigset_libc);
+ ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &sigset_libc, nullptr));
+ },
+ SignalMaskFunctionType::RtAware);
+}
+
+TEST(signal, pthread_sigmask_setmask_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset_t sigset_libc;
+ sigfillset(&sigset_libc);
+ ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &sigset_libc, nullptr));
+ },
+ sigset_type);
+}
+
+TEST(signal, pthread_sigmask64_setmask_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset64_t sigset_libc;
+ sigfillset64(&sigset_libc);
+ ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &sigset_libc, nullptr));
+ },
+ SignalMaskFunctionType::RtAware);
+}
+
+TEST(signal, sigprocmask_block_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset_t sigset_libc;
+ sigfillset(&sigset_libc);
+ ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &sigset_libc, nullptr));
+ },
+ sigset_type);
+}
+
+TEST(signal, sigprocmask64_block_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset64_t sigset_libc;
+ sigfillset64(&sigset_libc);
+ ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &sigset_libc, nullptr));
+ },
+ SignalMaskFunctionType::RtAware);
+}
+
+TEST(signal, pthread_sigmask_block_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset_t sigset_libc;
+ sigfillset(&sigset_libc);
+ ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &sigset_libc, nullptr));
+ },
+ sigset_type);
+}
+
+TEST(signal, pthread_sigmask64_block_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset64_t sigset_libc;
+ sigfillset64(&sigset_libc);
+ ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &sigset_libc, nullptr));
+ },
+ SignalMaskFunctionType::RtAware);
+}
+
+// glibc filters out signals via sigfillset, not the actual underlying functions.
+TEST(signal, sigset_filter) {
+#if defined(__BIONIC__)
+ TestSignalMaskFunction(
+ []() {
+ for (int i = 1; i <= 64; ++i) {
+ sigset(i, SIG_HOLD);
+ }
+ },
+ SignalMaskFunctionType::RtAware);
+#endif
+}
+
+TEST(signal, sighold_filter) {
+#if defined(__BIONIC__)
+ TestSignalMaskFunction(
+ []() {
+ for (int i = 1; i <= 64; ++i) {
+ sighold(i);
+ }
+ },
+ SignalMaskFunctionType::RtAware);
+#endif
+}
+
+#if defined(__BIONIC__)
+// Not exposed via headers, but the symbols are available if you declare them yourself.
+extern "C" int sigblock(int);
+extern "C" int sigsetmask(int);
+#endif
+
+TEST(signal, sigblock_filter) {
+#if defined(__BIONIC__)
+ TestSignalMaskFunction(
+ []() {
+ int mask = ~0U;
+ ASSERT_EQ(0, sigblock(mask));
+ },
+ SignalMaskFunctionType::RtNonaware);
+#endif
+}
+
+TEST(signal, sigsetmask_filter) {
+#if defined(__BIONIC__)
+ TestSignalMaskFunction(
+ []() {
+ int mask = ~0U;
+ ASSERT_EQ(0, sigsetmask(mask));
+ },
+ SignalMaskFunctionType::RtNonaware);
+#endif
+}
+
TEST(signal, sys_signame) {
#if defined(__BIONIC__)
ASSERT_TRUE(sys_signame[0] == NULL);
diff --git a/tests/spawn_test.cpp b/tests/spawn_test.cpp
index 84df16d..86175f9 100644
--- a/tests/spawn_test.cpp
+++ b/tests/spawn_test.cpp
@@ -20,7 +20,7 @@
#include <fcntl.h>
#include <gtest/gtest.h>
-#include "ScopedSignalHandler.h"
+#include "SignalUtils.h"
#include "utils.h"
#include <android-base/file.h>
diff --git a/tests/stack_unwinding_test.cpp b/tests/stack_unwinding_test.cpp
index bb58ae4..0ff6f30 100644
--- a/tests/stack_unwinding_test.cpp
+++ b/tests/stack_unwinding_test.cpp
@@ -29,7 +29,7 @@
#include <unistd.h>
#include <unwind.h>
-#include "ScopedSignalHandler.h"
+#include "SignalUtils.h"
#define noinline __attribute__((__noinline__))
#define __unused __attribute__((__unused__))
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index c1a51a8..33514d4 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -335,12 +335,10 @@
TEST(STDIO_TEST, snprintf_n) {
#if defined(__BIONIC__)
- // http://b/14492135
+ // http://b/14492135 and http://b/31832608.
char buf[32];
int i = 1234;
- EXPECT_EQ(5, snprintf(buf, sizeof(buf), "a %n b", &i));
- EXPECT_EQ(1234, i);
- EXPECT_STREQ("a n b", buf);
+ EXPECT_DEATH(snprintf(buf, sizeof(buf), "a %n b", &i), "%n not allowed on Android");
#else
GTEST_LOG_(INFO) << "This test does nothing on glibc.\n";
#endif
diff --git a/tests/sys_ioctl_diag_test.cpp b/tests/sys_ioctl_diag_test.cpp
new file mode 100644
index 0000000..e271e6c
--- /dev/null
+++ b/tests/sys_ioctl_diag_test.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// This file makes uses of clang's built-in diagnostic checker.
+// While not officially supported by clang, it's used by clang for all of its
+// own diagnostic tests. Please see
+// https://clang.llvm.org/doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details
+// for details.
+
+// expected-no-diagnostics
+
+#include <sys/ioctl.h>
+
+#pragma clang diagnostic warning "-Wsign-conversion"
+
+void check_no_signedness_warnings(int i, unsigned x) {
+ ioctl(i, i);
+ ioctl(i, x);
+
+ ioctl(i, i, nullptr);
+ ioctl(i, x, nullptr);
+}
diff --git a/tests/sys_signalfd_test.cpp b/tests/sys_signalfd_test.cpp
index 67a72e0..179fcf9 100644
--- a/tests/sys_signalfd_test.cpp
+++ b/tests/sys_signalfd_test.cpp
@@ -36,7 +36,7 @@
#include <thread>
-#include "ScopedSignalHandler.h"
+#include "SignalUtils.h"
static void TestSignalFd(int fd, int signal) {
ASSERT_NE(-1, fd) << strerror(errno);
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 2b9935a..3196f34 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -26,7 +26,7 @@
#include <unistd.h>
#include <atomic>
-#include "ScopedSignalHandler.h"
+#include "SignalUtils.h"
#include "utils.h"
#include "private/bionic_constants.h"
@@ -871,3 +871,54 @@
ASSERT_EQ(buf, ctime_r(&t, buf));
ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", buf);
}
+
+// https://issuetracker.google.com/37128336
+TEST(time, strftime_strptime_s) {
+ char buf[32];
+ const struct tm tm0 = { .tm_year = 1982-1900, .tm_mon = 0, .tm_mday = 1 };
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ strftime(buf, sizeof(buf), "<%s>", &tm0);
+ EXPECT_STREQ("<378720000>", buf);
+
+ setenv("TZ", "UTC", 1);
+ strftime(buf, sizeof(buf), "<%s>", &tm0);
+ EXPECT_STREQ("<378691200>", buf);
+
+ struct tm tm;
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+ memset(&tm, 0xff, sizeof(tm));
+ char* p = strptime("378720000x", "%s", &tm);
+ ASSERT_EQ('x', *p);
+ EXPECT_EQ(0, tm.tm_sec);
+ EXPECT_EQ(0, tm.tm_min);
+ EXPECT_EQ(0, tm.tm_hour);
+ EXPECT_EQ(1, tm.tm_mday);
+ EXPECT_EQ(0, tm.tm_mon);
+ EXPECT_EQ(82, tm.tm_year);
+ EXPECT_EQ(5, tm.tm_wday);
+ EXPECT_EQ(0, tm.tm_yday);
+ EXPECT_EQ(0, tm.tm_isdst);
+
+ setenv("TZ", "UTC", 1);
+ tzset();
+ memset(&tm, 0xff, sizeof(tm));
+ p = strptime("378691200x", "%s", &tm);
+ ASSERT_EQ('x', *p);
+ EXPECT_EQ(0, tm.tm_sec);
+ EXPECT_EQ(0, tm.tm_min);
+ EXPECT_EQ(0, tm.tm_hour);
+ EXPECT_EQ(1, tm.tm_mday);
+ EXPECT_EQ(0, tm.tm_mon);
+ EXPECT_EQ(82, tm.tm_year);
+ EXPECT_EQ(5, tm.tm_wday);
+ EXPECT_EQ(0, tm.tm_yday);
+ EXPECT_EQ(0, tm.tm_isdst);
+}
+
+TEST(time, strptime_s_nothing) {
+ struct tm tm;
+ ASSERT_EQ(nullptr, strptime("x", "%s", &tm));
+}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 912ea0c..db4859b 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -17,7 +17,7 @@
#include <gtest/gtest.h>
#include "BionicDeathTest.h"
-#include "ScopedSignalHandler.h"
+#include "SignalUtils.h"
#include "TemporaryFile.h"
#include "utils.h"