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"