Merge "move arch variant structs down a level"
diff --git a/libc/Android.mk b/libc/Android.mk
index 99a841a..2d97f35 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -625,6 +625,11 @@
   use_clang := false
 endif
 
+# b/25291096, Clang/llvm compiled libc.so for mips/mips64 failed to boot.
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),mips mips64))
+  use_clang := false
+endif
+
 ifeq ($(use_clang),)
   use_clang := false
 endif
diff --git a/libc/bionic/__cxa_guard.cpp b/libc/bionic/__cxa_guard.cpp
index 5b34b58..97284d5 100644
--- a/libc/bionic/__cxa_guard.cpp
+++ b/libc/bionic/__cxa_guard.cpp
@@ -109,7 +109,7 @@
       }
     }
 
-    __futex_wait_ex(&gv->state, false, CONSTRUCTION_UNDERWAY_WITH_WAITER, NULL);
+    __futex_wait_ex(&gv->state, false, CONSTRUCTION_UNDERWAY_WITH_WAITER, false, nullptr);
     old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
   }
 }
diff --git a/libc/bionic/bionic_time_conversions.cpp b/libc/bionic/bionic_time_conversions.cpp
index 75e8d49..f3ca46a 100644
--- a/libc/bionic/bionic_time_conversions.cpp
+++ b/libc/bionic/bionic_time_conversions.cpp
@@ -52,18 +52,12 @@
   tv.tv_usec = ts.tv_nsec / 1000;
 }
 
-// Initializes 'ts' with the difference between 'abs_ts' and the current time
-// according to 'clock'. Returns false if abstime already expired, true otherwise.
-bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock) {
-  clock_gettime(clock, &ts);
-  ts.tv_sec = abs_ts.tv_sec - ts.tv_sec;
-  ts.tv_nsec = abs_ts.tv_nsec - ts.tv_nsec;
-  if (ts.tv_nsec < 0) {
-    ts.tv_sec--;
-    ts.tv_nsec += NS_PER_S;
+void absolute_timespec_from_timespec(timespec& abs_ts, const timespec& ts, clockid_t clock) {
+  clock_gettime(clock, &abs_ts);
+  abs_ts.tv_sec += ts.tv_sec;
+  abs_ts.tv_nsec += ts.tv_nsec;
+  if (abs_ts.tv_nsec >= NS_PER_S) {
+    abs_ts.tv_nsec -= NS_PER_S;
+    abs_ts.tv_sec++;
   }
-  if (ts.tv_nsec < 0 || ts.tv_sec < 0) {
-    return false;
-  }
-  return true;
 }
diff --git a/libc/bionic/flockfile.cpp b/libc/bionic/flockfile.cpp
index b73907cb..db68801 100644
--- a/libc/bionic/flockfile.cpp
+++ b/libc/bionic/flockfile.cpp
@@ -40,7 +40,7 @@
     __sinit();
   }
 
-  if (fp != NULL) {
+  if (fp != nullptr) {
     pthread_mutex_lock(&_FLOCK(fp));
   }
 }
@@ -52,7 +52,7 @@
 
   // The specification for ftrylockfile() says it returns 0 on success,
   // or non-zero on error. So return an errno code directly on error.
-  if (fp == NULL) {
+  if (fp == nullptr) {
     return EINVAL;
   }
 
@@ -64,7 +64,7 @@
     __sinit();
   }
 
-  if (fp != NULL) {
+  if (fp != nullptr) {
     pthread_mutex_unlock(&_FLOCK(fp));
   }
 }
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index a683748..8f1ee95 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -110,6 +110,7 @@
   // Initialize libc globals that are needed in both the linker and in libc.
   // In dynamic binaries, this is run at least twice for different copies of the
   // globals, once for the linker's copy and once for the one in libc.so.
+  __libc_auxv = args.auxv;
   __libc_globals.initialize();
   __libc_globals.mutate([&args](libc_globals* globals) {
     __libc_init_vdso(globals, args);
@@ -121,7 +122,6 @@
   // Initialize various globals.
   environ = args.envp;
   errno = 0;
-  __libc_auxv = args.auxv;
   __progname = args.argv[0] ? args.argv[0] : "<unknown>";
   __abort_message_ptr = args.abort_message_ptr;
 
diff --git a/libc/bionic/mmap.cpp b/libc/bionic/mmap.cpp
index 9bc80a2..57a8cdf 100644
--- a/libc/bionic/mmap.cpp
+++ b/libc/bionic/mmap.cpp
@@ -27,6 +27,7 @@
  */
 
 #include <errno.h>
+#include <stdint.h>
 #include <sys/mman.h>
 #include <unistd.h>
 
@@ -53,10 +54,14 @@
     return MAP_FAILED;
   }
 
-  bool is_private_anonymous = (flags & (MAP_PRIVATE | MAP_ANONYMOUS)) != 0;
+  bool is_private_anonymous =
+      (flags & (MAP_PRIVATE | MAP_ANONYMOUS)) == (MAP_PRIVATE | MAP_ANONYMOUS);
+  bool is_stack_or_grows_down = (flags & (MAP_STACK | MAP_GROWSDOWN)) != 0;
+
   void* result = __mmap2(addr, size, prot, flags, fd, offset >> MMAP2_SHIFT);
 
-  if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE && is_private_anonymous) {
+  if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE &&
+      is_private_anonymous && !is_stack_or_grows_down) {
     ErrnoRestorer errno_restorer;
     int rc = madvise(result, size, MADV_MERGEABLE);
     if (rc == -1 && errno == EINVAL) {
diff --git a/libc/bionic/mremap.cpp b/libc/bionic/mremap.cpp
index 4892b1d..6653d43 100644
--- a/libc/bionic/mremap.cpp
+++ b/libc/bionic/mremap.cpp
@@ -26,12 +26,24 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <sys/mman.h>
 #include <stdarg.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "private/bionic_macros.h"
 
 extern "C" void* ___mremap(void*, size_t, size_t, int, void*);
 
 void* mremap(void* old_address, size_t old_size, size_t new_size, int flags, ...) {
+  // prevent allocations large enough for `end - start` to overflow
+  size_t rounded = BIONIC_ALIGN(new_size, PAGE_SIZE);
+  if (rounded < new_size || rounded > PTRDIFF_MAX) {
+    errno = ENOMEM;
+    return MAP_FAILED;
+  }
+
   void* new_address = nullptr;
   // The optional argument is only valid if the MREMAP_FIXED flag is set,
   // so we assume it's not present otherwise.
diff --git a/libc/bionic/pthread_barrier.cpp b/libc/bionic/pthread_barrier.cpp
index 3227daf..1bcd12a 100644
--- a/libc/bionic/pthread_barrier.cpp
+++ b/libc/bionic/pthread_barrier.cpp
@@ -118,7 +118,7 @@
   // threads have left the barrier. Use acquire operation here to synchronize with
   // the last thread leaving the previous cycle, so we can read correct wait_count below.
   while(atomic_load_explicit(&barrier->state, memory_order_acquire) == RELEASE) {
-    __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, nullptr);
+    __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, false, nullptr);
   }
 
   uint32_t prev_wait_count = atomic_load_explicit(&barrier->wait_count, memory_order_relaxed);
@@ -152,7 +152,7 @@
     // Use acquire operation here to synchronize between the last thread entering the
     // barrier with all threads leaving the barrier.
     while (atomic_load_explicit(&barrier->state, memory_order_acquire) == WAIT) {
-      __futex_wait_ex(&barrier->state, barrier->pshared, WAIT, nullptr);
+      __futex_wait_ex(&barrier->state, barrier->pshared, WAIT, false, nullptr);
     }
   }
   // Use release operation here to make it not reordered with previous operations.
@@ -173,7 +173,7 @@
   // Use acquire operation here to synchronize with the last thread leaving the barrier.
   // So we can read correct wait_count below.
   while (atomic_load_explicit(&barrier->state, memory_order_acquire) == RELEASE) {
-    __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, nullptr);
+    __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, false, nullptr);
   }
   if (atomic_load_explicit(&barrier->wait_count, memory_order_relaxed) != 0) {
     return EBUSY;
diff --git a/libc/bionic/pthread_cond.cpp b/libc/bionic/pthread_cond.cpp
index 4a69da5..adbce07 100644
--- a/libc/bionic/pthread_cond.cpp
+++ b/libc/bionic/pthread_cond.cpp
@@ -111,8 +111,8 @@
     return COND_IS_SHARED(atomic_load_explicit(&state, memory_order_relaxed));
   }
 
-  int get_clock() {
-    return COND_GET_CLOCK(atomic_load_explicit(&state, memory_order_relaxed));
+  bool use_realtime_clock() {
+    return COND_GET_CLOCK(atomic_load_explicit(&state, memory_order_relaxed)) == CLOCK_REALTIME;
   }
 
 #if defined(__LP64__)
@@ -170,12 +170,17 @@
   return 0;
 }
 
-static int __pthread_cond_timedwait_relative(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
-                                             const timespec* rel_timeout_or_null) {
-  unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
+static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
+                                    bool use_realtime_clock, const timespec* abs_timeout_or_null) {
+  int result = check_timespec(abs_timeout_or_null);
+  if (result != 0) {
+    return result;
+  }
 
+  unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
   pthread_mutex_unlock(mutex);
-  int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state, rel_timeout_or_null);
+  int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state,
+                               use_realtime_clock, abs_timeout_or_null);
   pthread_mutex_lock(mutex);
 
   if (status == -ETIMEDOUT) {
@@ -184,21 +189,6 @@
   return 0;
 }
 
-static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex_t* mutex,
-                                    const timespec* abs_timeout_or_null, clockid_t clock) {
-  timespec ts;
-  timespec* rel_timeout = NULL;
-
-  if (abs_timeout_or_null != NULL) {
-    rel_timeout = &ts;
-    if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
-      return ETIMEDOUT;
-    }
-  }
-
-  return __pthread_cond_timedwait_relative(cond, mutex, rel_timeout);
-}
-
 int pthread_cond_broadcast(pthread_cond_t* cond_interface) {
   return __pthread_cond_pulse(__get_internal_cond(cond_interface), INT_MAX);
 }
@@ -209,14 +199,14 @@
 
 int pthread_cond_wait(pthread_cond_t* cond_interface, pthread_mutex_t* mutex) {
   pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
-  return __pthread_cond_timedwait(cond, mutex, NULL, cond->get_clock());
+  return __pthread_cond_timedwait(cond, mutex, false, nullptr);
 }
 
 int pthread_cond_timedwait(pthread_cond_t *cond_interface, pthread_mutex_t * mutex,
                            const timespec *abstime) {
 
   pthread_cond_internal_t* cond = __get_internal_cond(cond_interface);
-  return __pthread_cond_timedwait(cond, mutex, abstime, cond->get_clock());
+  return __pthread_cond_timedwait(cond, mutex, cond->use_realtime_clock(), abstime);
 }
 
 #if !defined(__LP64__)
@@ -225,8 +215,7 @@
                                                 pthread_mutex_t* mutex,
                                                 const timespec* abs_timeout) {
 
-  return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, abs_timeout,
-                                  CLOCK_MONOTONIC);
+  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,
@@ -238,8 +227,13 @@
 extern "C" int pthread_cond_timedwait_relative_np(pthread_cond_t* cond_interface,
                                                   pthread_mutex_t* mutex,
                                                   const timespec* rel_timeout) {
-
-  return __pthread_cond_timedwait_relative(__get_internal_cond(cond_interface), mutex, rel_timeout);
+  timespec ts;
+  timespec* abs_timeout = nullptr;
+  if (rel_timeout != nullptr) {
+    absolute_timespec_from_timespec(ts, *rel_timeout, CLOCK_REALTIME);
+    abs_timeout = &ts;
+  }
+  return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, true, abs_timeout);
 }
 
 extern "C" int pthread_cond_timeout_np(pthread_cond_t* cond_interface,
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index 3da4bcf..cad138c 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -299,11 +299,15 @@
  */
 static inline __always_inline int __pthread_normal_mutex_lock(pthread_mutex_internal_t* mutex,
                                                               uint16_t shared,
-                                                              const timespec* abs_timeout_or_null,
-                                                              clockid_t clock) {
+                                                              bool use_realtime_clock,
+                                                              const timespec* abs_timeout_or_null) {
     if (__predict_true(__pthread_normal_mutex_trylock(mutex, shared) == 0)) {
         return 0;
     }
+    int result = check_timespec(abs_timeout_or_null);
+    if (result != 0) {
+        return result;
+    }
 
     ScopedTrace trace("Contending for pthread mutex");
 
@@ -320,15 +324,8 @@
     // made by other threads visible to the current CPU.
     while (atomic_exchange_explicit(&mutex->state, locked_contended,
                                     memory_order_acquire) != unlocked) {
-        timespec ts;
-        timespec* rel_timeout = NULL;
-        if (abs_timeout_or_null != NULL) {
-            rel_timeout = &ts;
-            if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
-                return ETIMEDOUT;
-            }
-        }
-        if (__futex_wait_ex(&mutex->state, shared, locked_contended, rel_timeout) == -ETIMEDOUT) {
+        if (__futex_wait_ex(&mutex->state, shared, locked_contended, use_realtime_clock,
+                            abs_timeout_or_null) == -ETIMEDOUT) {
             return ETIMEDOUT;
         }
     }
@@ -399,14 +396,15 @@
                                                       pthread_mutex_internal_t* mutex,
                                                       uint16_t shared,
                                                       uint16_t old_state,
-                                                      const timespec* rel_timeout) {
+                                                      bool use_realtime_clock,
+                                                      const timespec* abs_timeout) {
 // __futex_wait always waits on a 32-bit value. But state is 16-bit. For a normal mutex, the owner_tid
 // field in mutex is not used. On 64-bit devices, the __pad field in mutex is not used.
 // But when a recursive or errorcheck mutex is used on 32-bit devices, we need to add the
 // owner_tid value in the value argument for __futex_wait, otherwise we may always get EAGAIN error.
 
 #if defined(__LP64__)
-  return __futex_wait_ex(&mutex->state, shared, old_state, rel_timeout);
+  return __futex_wait_ex(&mutex->state, shared, old_state, use_realtime_clock, abs_timeout);
 
 #else
   // This implementation works only when the layout of pthread_mutex_internal_t matches below expectation.
@@ -415,19 +413,21 @@
   static_assert(offsetof(pthread_mutex_internal_t, owner_tid) == 2, "");
 
   uint32_t owner_tid = atomic_load_explicit(&mutex->owner_tid, memory_order_relaxed);
-  return __futex_wait_ex(&mutex->state, shared, (owner_tid << 16) | old_state, rel_timeout);
+  return __futex_wait_ex(&mutex->state, shared, (owner_tid << 16) | old_state,
+                         use_realtime_clock, abs_timeout);
 #endif
 }
 
 static int __pthread_mutex_lock_with_timeout(pthread_mutex_internal_t* mutex,
-                                           const timespec* abs_timeout_or_null, clockid_t clock) {
+                                             bool use_realtime_clock,
+                                             const timespec* abs_timeout_or_null) {
     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);
 
     // Handle common case first.
     if ( __predict_true(mtype == MUTEX_TYPE_BITS_NORMAL) ) {
-        return __pthread_normal_mutex_lock(mutex, shared, abs_timeout_or_null, clock);
+        return __pthread_normal_mutex_lock(mutex, shared, use_realtime_clock, abs_timeout_or_null);
     }
 
     // Do we already own this recursive or error-check mutex?
@@ -487,16 +487,13 @@
             old_state = new_state;
         }
 
-        // We are in locked_contended state, sleep until someone wakes us up.
-        timespec ts;
-        timespec* rel_timeout = NULL;
-        if (abs_timeout_or_null != NULL) {
-            rel_timeout = &ts;
-            if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, clock)) {
-                return ETIMEDOUT;
-            }
+        int result = check_timespec(abs_timeout_or_null);
+        if (result != 0) {
+            return result;
         }
-        if (__recursive_or_errorcheck_mutex_wait(mutex, shared, old_state, rel_timeout) == -ETIMEDOUT) {
+        // We are in locked_contended state, sleep until someone wakes us up.
+        if (__recursive_or_errorcheck_mutex_wait(mutex, shared, old_state, use_realtime_clock,
+                                                 abs_timeout_or_null) == -ETIMEDOUT) {
             return ETIMEDOUT;
         }
         old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
@@ -521,7 +518,7 @@
         return 0;
       }
     }
-    return __pthread_mutex_lock_with_timeout(mutex, NULL, 0);
+    return __pthread_mutex_lock_with_timeout(mutex, false, nullptr);
 }
 
 int pthread_mutex_unlock(pthread_mutex_t* mutex_interface) {
@@ -616,17 +613,12 @@
 
 #if !defined(__LP64__)
 extern "C" int pthread_mutex_lock_timeout_np(pthread_mutex_t* mutex_interface, unsigned ms) {
+    timespec ts;
+    timespec_from_ms(ts, ms);
     timespec abs_timeout;
-    clock_gettime(CLOCK_MONOTONIC, &abs_timeout);
-    abs_timeout.tv_sec  += ms / 1000;
-    abs_timeout.tv_nsec += (ms % 1000) * 1000000;
-    if (abs_timeout.tv_nsec >= NS_PER_S) {
-        abs_timeout.tv_sec++;
-        abs_timeout.tv_nsec -= NS_PER_S;
-    }
-
+    absolute_timespec_from_timespec(abs_timeout, ts, CLOCK_MONOTONIC);
     int error = __pthread_mutex_lock_with_timeout(__get_internal_mutex(mutex_interface),
-                                                  &abs_timeout, CLOCK_MONOTONIC);
+                                                  false, &abs_timeout);
     if (error == ETIMEDOUT) {
         error = EBUSY;
     }
@@ -636,7 +628,7 @@
 
 int pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, const timespec* abs_timeout) {
     return __pthread_mutex_lock_with_timeout(__get_internal_mutex(mutex_interface),
-                                             abs_timeout, CLOCK_REALTIME);
+                                             true, abs_timeout);
 }
 
 int pthread_mutex_destroy(pthread_mutex_t* mutex_interface) {
diff --git a/libc/bionic/pthread_once.cpp b/libc/bionic/pthread_once.cpp
index 7688a23..f48eadc 100644
--- a/libc/bionic/pthread_once.cpp
+++ b/libc/bionic/pthread_once.cpp
@@ -79,7 +79,7 @@
     }
 
     // The initialization is underway, wait for its finish.
-    __futex_wait_ex(once_control_ptr, 0, old_value, NULL);
+    __futex_wait_ex(once_control_ptr, 0, old_value, false, nullptr);
     old_value = atomic_load_explicit(once_control_ptr, memory_order_acquire);
   }
 }
diff --git a/libc/bionic/pthread_rwlock.cpp b/libc/bionic/pthread_rwlock.cpp
index 934210e..b1c48c8 100644
--- a/libc/bionic/pthread_rwlock.cpp
+++ b/libc/bionic/pthread_rwlock.cpp
@@ -294,9 +294,13 @@
   }
 
   while (true) {
-    int ret = __pthread_rwlock_tryrdlock(rwlock);
-    if (ret == 0 || ret == EAGAIN) {
-      return ret;
+    int result = __pthread_rwlock_tryrdlock(rwlock);
+    if (result == 0 || result == EAGAIN) {
+      return result;
+    }
+    result = check_timespec(abs_timeout_or_null);
+    if (result != 0) {
+      return result;
     }
 
     int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
@@ -304,16 +308,6 @@
       continue;
     }
 
-    timespec ts;
-    timespec* rel_timeout = NULL;
-
-    if (abs_timeout_or_null != NULL) {
-      rel_timeout = &ts;
-      if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, CLOCK_REALTIME)) {
-        return ETIMEDOUT;
-      }
-    }
-
     rwlock->pending_lock.lock();
     rwlock->pending_reader_count++;
 
@@ -327,10 +321,10 @@
     int old_serial = rwlock->pending_reader_wakeup_serial;
     rwlock->pending_lock.unlock();
 
-    int futex_ret = 0;
+    int futex_result = 0;
     if (!__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred)) {
-      futex_ret = __futex_wait_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared,
-                                  old_serial, rel_timeout);
+      futex_result = __futex_wait_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared,
+                                  old_serial, true, abs_timeout_or_null);
     }
 
     rwlock->pending_lock.lock();
@@ -341,7 +335,7 @@
     }
     rwlock->pending_lock.unlock();
 
-    if (futex_ret == -ETIMEDOUT) {
+    if (futex_result == -ETIMEDOUT) {
       return ETIMEDOUT;
     }
   }
@@ -372,9 +366,13 @@
     return EDEADLK;
   }
   while (true) {
-    int ret = __pthread_rwlock_trywrlock(rwlock);
-    if (ret == 0) {
-      return ret;
+    int result = __pthread_rwlock_trywrlock(rwlock);
+    if (result == 0) {
+      return result;
+    }
+    result = check_timespec(abs_timeout_or_null);
+    if (result != 0) {
+      return result;
     }
 
     int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed);
@@ -382,16 +380,6 @@
       continue;
     }
 
-    timespec ts;
-    timespec* rel_timeout = NULL;
-
-    if (abs_timeout_or_null != NULL) {
-      rel_timeout = &ts;
-      if (!timespec_from_absolute_timespec(*rel_timeout, *abs_timeout_or_null, CLOCK_REALTIME)) {
-        return ETIMEDOUT;
-      }
-    }
-
     rwlock->pending_lock.lock();
     rwlock->pending_writer_count++;
 
@@ -401,10 +389,10 @@
     int old_serial = rwlock->pending_writer_wakeup_serial;
     rwlock->pending_lock.unlock();
 
-    int futex_ret = 0;
+    int futex_result = 0;
     if (!__can_acquire_write_lock(old_state)) {
-      futex_ret = __futex_wait_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared,
-                                  old_serial, rel_timeout);
+      futex_result = __futex_wait_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared,
+                                  old_serial, true, abs_timeout_or_null);
     }
 
     rwlock->pending_lock.lock();
@@ -415,7 +403,7 @@
     }
     rwlock->pending_lock.unlock();
 
-    if (futex_ret == -ETIMEDOUT) {
+    if (futex_result == -ETIMEDOUT) {
       return ETIMEDOUT;
     }
   }
@@ -427,7 +415,7 @@
   if (__predict_true(__pthread_rwlock_tryrdlock(rwlock) == 0)) {
     return 0;
   }
-  return __pthread_rwlock_timedrdlock(rwlock, NULL);
+  return __pthread_rwlock_timedrdlock(rwlock, nullptr);
 }
 
 int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) {
@@ -446,7 +434,7 @@
   if (__predict_true(__pthread_rwlock_trywrlock(rwlock) == 0)) {
     return 0;
   }
-  return __pthread_rwlock_timedwrlock(rwlock, NULL);
+  return __pthread_rwlock_timedwrlock(rwlock, nullptr);
 }
 
 int pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) {
diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp
index ff84443..79b5d63 100644
--- a/libc/bionic/semaphore.cpp
+++ b/libc/bionic/semaphore.cpp
@@ -220,7 +220,7 @@
       return 0;
     }
 
-    __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, NULL);
+    __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, false, nullptr);
   }
 }
 
@@ -235,36 +235,29 @@
   }
 
   // Check it as per POSIX.
-  if (abs_timeout == NULL || abs_timeout->tv_sec < 0 || abs_timeout->tv_nsec < 0 || abs_timeout->tv_nsec >= NS_PER_S) {
-    errno = EINVAL;
+  int result = check_timespec(abs_timeout);
+  if (result != 0) {
+    errno = result;
     return -1;
   }
 
   unsigned int shared = SEM_GET_SHARED(sem_count_ptr);
 
   while (true) {
-    // POSIX mandates CLOCK_REALTIME here.
-    timespec ts;
-    if (!timespec_from_absolute_timespec(ts, *abs_timeout, CLOCK_REALTIME)) {
-      errno = ETIMEDOUT;
-      return -1;
-    }
-
     // Try to grab the semaphore. If the value was 0, this will also change it to -1.
     if (__sem_dec(sem_count_ptr) > 0) {
-      break;
+      return 0;
     }
 
     // Contention detected. Wait for a wakeup event.
-    int ret = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, &ts);
+    int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, true, abs_timeout);
 
     // Return in case of timeout or interrupt.
-    if (ret == -ETIMEDOUT || ret == -EINTR) {
-      errno = -ret;
+    if (result == -ETIMEDOUT || result == -EINTR) {
+      errno = -result;
       return -1;
     }
   }
-  return 0;
 }
 
 int sem_post(sem_t* sem) {
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index d59de29..ed9a3b9 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -131,12 +131,16 @@
 extern void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo);
 
 /*
- * Initializes public namespace. The path is the list of sonames
- * separated by colon. Example: "libc.so:libm.so:libdl.so".
- *
+ * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
+ * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
  * The libraries in this list should be loaded prior to this call.
+ *
+ * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
+ * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
  */
-extern bool android_init_public_namespace(const char* path);
+extern bool android_init_namespaces(const char* public_ns_sonames,
+                                    const char* anon_ns_library_path);
 
 /*
  * Creates new linker namespace.
diff --git a/libc/private/bionic_futex.h b/libc/private/bionic_futex.h
index 401577a..946d9dd 100644
--- a/libc/private/bionic_futex.h
+++ b/libc/private/bionic_futex.h
@@ -40,10 +40,12 @@
 
 struct timespec;
 
-static inline __always_inline int __futex(volatile void* ftx, int op, int value, const struct timespec* timeout) {
+static inline __always_inline int __futex(volatile void* ftx, int op, int value,
+                                          const struct timespec* timeout,
+                                          int bitset) {
   // Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
   int saved_errno = errno;
-  int result = syscall(__NR_futex, ftx, op, value, timeout);
+  int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);
   if (__predict_false(result == -1)) {
     result = -errno;
     errno = saved_errno;
@@ -52,19 +54,22 @@
 }
 
 static inline int __futex_wake(volatile void* ftx, int count) {
-  return __futex(ftx, FUTEX_WAKE, count, NULL);
+  return __futex(ftx, FUTEX_WAKE, count, NULL, 0);
 }
 
 static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) {
-  return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL);
+  return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL, 0);
 }
 
 static inline int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
-  return __futex(ftx, FUTEX_WAIT, value, timeout);
+  return __futex(ftx, FUTEX_WAIT, value, timeout, 0);
 }
 
-static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value, const struct timespec* timeout) {
-  return __futex(ftx, shared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE, value, timeout);
+static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value,
+                                  bool use_realtime_clock, const struct timespec* abs_timeout) {
+  return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE) |
+                 (use_realtime_clock ? FUTEX_CLOCK_REALTIME : 0), value, abs_timeout,
+                 FUTEX_BITSET_MATCH_ANY);
 }
 
 __END_DECLS
diff --git a/libc/private/bionic_lock.h b/libc/private/bionic_lock.h
index 238ace4..3dbafe0 100644
--- a/libc/private/bionic_lock.h
+++ b/libc/private/bionic_lock.h
@@ -64,7 +64,7 @@
     }
     while (atomic_exchange_explicit(&state, LockedWithWaiter, memory_order_acquire) != Unlocked) {
       // TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
-      __futex_wait_ex(&state, process_shared, LockedWithWaiter, NULL);
+      __futex_wait_ex(&state, process_shared, LockedWithWaiter, false, nullptr);
     }
     return;
   }
diff --git a/libc/private/bionic_time_conversions.h b/libc/private/bionic_time_conversions.h
index cf0046a..294c29a 100644
--- a/libc/private/bionic_time_conversions.h
+++ b/libc/private/bionic_time_conversions.h
@@ -29,9 +29,12 @@
 #ifndef _BIONIC_TIME_CONVERSIONS_H
 #define _BIONIC_TIME_CONVERSIONS_H
 
+#include <errno.h>
 #include <time.h>
 #include <sys/cdefs.h>
 
+#include "private/bionic_constants.h"
+
 __BEGIN_DECLS
 
 __LIBC_HIDDEN__ bool timespec_from_timeval(timespec& ts, const timeval& tv);
@@ -39,8 +42,21 @@
 
 __LIBC_HIDDEN__ void timeval_from_timespec(timeval& tv, const timespec& ts);
 
-__LIBC_HIDDEN__ bool timespec_from_absolute_timespec(timespec& ts, const timespec& abs_ts, clockid_t clock);
+__LIBC_HIDDEN__ void absolute_timespec_from_timespec(timespec& abs_ts, const timespec& ts,
+                                                     clockid_t clock);
 
 __END_DECLS
 
+static inline int check_timespec(const timespec* ts) {
+  if (ts != nullptr) {
+    if (ts->tv_nsec < 0 || ts->tv_nsec >= NS_PER_S) {
+      return EINVAL;
+    }
+    if (ts->tv_sec < 0) {
+      return ETIMEDOUT;
+    }
+  }
+  return 0;
+}
+
 #endif
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index ced94e3..3ae7059 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -109,7 +109,7 @@
   pthread_mutex_t _lock;
 
   /* __fsetlocking support */
-  bool _stdio_handles_locking;
+  bool _caller_handles_locking;
 };
 
 #if defined(__cplusplus)
@@ -131,7 +131,7 @@
 	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
 	pthread_mutex_init(&_FLOCK(fp), &attr); \
 	pthread_mutexattr_destroy(&attr); \
-	_EXT(fp)->_stdio_handles_locking = true; \
+	_EXT(fp)->_caller_handles_locking = false; \
 } while (0)
 
 #define _FILEEXT_SETUP(f, fext) \
@@ -208,8 +208,8 @@
 	(fp)->_lb._base = NULL; \
 }
 
-#define FLOCKFILE(fp)   if (_EXT(fp)->_stdio_handles_locking) flockfile(fp)
-#define FUNLOCKFILE(fp) if (_EXT(fp)->_stdio_handles_locking) funlockfile(fp)
+#define FLOCKFILE(fp)   if (!_EXT(fp)->_caller_handles_locking) flockfile(fp)
+#define FUNLOCKFILE(fp) if (!_EXT(fp)->_caller_handles_locking) funlockfile(fp)
 
 #define FLOATING_POINT
 #define PRINTF_WIDE_CHAR
diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
index 310076a..f273d45 100644
--- a/libc/stdio/stdio_ext.cpp
+++ b/libc/stdio/stdio_ext.cpp
@@ -74,7 +74,7 @@
 }
 
 int __fsetlocking(FILE* fp, int type) {
-  int old_state = _EXT(fp)->_stdio_handles_locking ? FSETLOCKING_INTERNAL : FSETLOCKING_BYCALLER;
+  int old_state = _EXT(fp)->_caller_handles_locking ? FSETLOCKING_BYCALLER : FSETLOCKING_INTERNAL;
   if (type == FSETLOCKING_QUERY) {
     return old_state;
   }
@@ -84,7 +84,7 @@
     __libc_fatal("Bad type (%d) passed to __fsetlocking", type);
   }
 
-  _EXT(fp)->_stdio_handles_locking = (type == FSETLOCKING_INTERNAL);
+  _EXT(fp)->_caller_handles_locking = (type == FSETLOCKING_BYCALLER);
   return old_state;
 }
 
diff --git a/libdl/Android.mk b/libdl/Android.mk
index 9a9c756..1ea5dc7 100644
--- a/libdl/Android.mk
+++ b/libdl/Android.mk
@@ -33,7 +33,13 @@
 LOCAL_CXX_STL := none
 
 LOCAL_MODULE := libdl
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk \
+                                 $(LOCAL_PATH)/libdl.arm.map \
+                                 $(LOCAL_PATH)/libdl.arm64.map \
+                                 $(LOCAL_PATH)/libdl.mips.map \
+                                 $(LOCAL_PATH)/libdl.mips64.map \
+                                 $(LOCAL_PATH)/libdl.x86.map \
+                                 $(LOCAL_PATH)/libdl.x86_64.map \
 
 # NOTE: libdl needs __aeabi_unwind_cpp_pr0 from libgcc.a but libgcc.a needs a
 # few symbols from libc. Using --no-undefined here results in having to link
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 3417f99..5ad9f9d 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -16,7 +16,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.c b/libdl/libdl.c
index 3cde5eb..3928ba2 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -49,7 +49,11 @@
 void android_set_application_target_sdk_version(uint32_t target __unused) { }
 uint32_t android_get_application_target_sdk_version() { return 0; }
 
-bool android_init_public_namespace(const char* paths __unused) { return false; }
+bool android_init_namespaces(const char* public_ns_sonames __unused,
+                             const char* anon_ns_library_path __unused) {
+  return false;
+}
+
 struct android_namespace_t* android_create_namespace(const char* name __unused,
                                                      const char* ld_library_path __unused,
                                                      const char* default_library_path __unused,
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 421d825..8d123fe 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -30,7 +30,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index b7e9aec..3535774 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -15,7 +15,7 @@
 
 LIBC_N {
   global:
-    android_init_public_namespace;
+    android_init_namespaces;
     android_create_namespace;
 } LIBC;
 
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 7957921..d07ec86 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -89,9 +89,12 @@
   return dlopen_ext(filename, flags, nullptr, caller_addr);
 }
 
+extern android_namespace_t* g_anonymous_namespace;
+
 void* dlsym(void* handle, const char* symbol) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
 
+  // TODO(dimitry): move (most of) the code below to linker.cpp
 #if !defined(__LP64__)
   if (handle == nullptr) {
     __bionic_format_dlerror("dlsym library handle is null", nullptr);
@@ -108,16 +111,10 @@
   const ElfW(Sym)* sym = nullptr;
   void* caller_addr = __builtin_return_address(0);
   soinfo* caller = find_containing_library(caller_addr);
-  if (caller == nullptr) {
-    char buf[256];
-    __libc_format_buffer(buf, sizeof(buf), "dlsym couldn't locate its caller address=%p; "
-                         "the caller was code not loaded by the dynamic linker", caller_addr);
-    __bionic_format_dlerror(buf, nullptr);
-    return nullptr;
-  }
+  android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
 
   if (handle == RTLD_DEFAULT || handle == RTLD_NEXT) {
-    sym = dlsym_linear_lookup(caller->get_namespace(), symbol, &found, caller, handle);
+    sym = dlsym_linear_lookup(ns, symbol, &found, caller, handle);
   } else {
     sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
   }
@@ -184,11 +181,12 @@
   return get_application_target_sdk_version();
 }
 
-bool android_init_public_namespace(const char* path) {
+bool android_init_namespaces(const char* public_ns_sonames,
+                             const char* anon_ns_library_path) {
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
-  bool success = init_public_namespace(path);
+  bool success = init_namespaces(public_ns_sonames, anon_ns_library_path);
   if (!success) {
-    __bionic_format_dlerror("android_init_public_namespace failed", linker_get_error_buffer());
+    __bionic_format_dlerror("android_init_namespaces failed", linker_get_error_buffer());
   }
 
   return success;
@@ -234,11 +232,11 @@
   // 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
   // 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
     "erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
-  // 0000000000111111 111122222222223333333333444444 4444555555555566666666667
-  // 0123456789012345 678901234567890123456789012345 6789012345678901234567890
-    "get_sdk_version\0android_init_public_namespace\0android_create_namespace\0"
+  // 0000000000111111 111122222222223333333333 4444444444555555555566666
+  // 0123456789012345 678901234567890123456789 0123456789012345678901234
+    "get_sdk_version\0android_init_namespaces\0android_create_namespace\0"
 #if defined(__arm__)
-  // 271
+  // 265
     "dl_unwind_find_exidx\0"
 #endif
     ;
@@ -260,10 +258,10 @@
   ELFW(SYM_INITIALIZER)(111, &android_dlopen_ext, 1),
   ELFW(SYM_INITIALIZER)(130, &android_set_application_target_sdk_version, 1),
   ELFW(SYM_INITIALIZER)(173, &android_get_application_target_sdk_version, 1),
-  ELFW(SYM_INITIALIZER)(216, &android_init_public_namespace, 1),
-  ELFW(SYM_INITIALIZER)(246, &android_create_namespace, 1),
+  ELFW(SYM_INITIALIZER)(216, &android_init_namespaces, 1),
+  ELFW(SYM_INITIALIZER)(240, &android_create_namespace, 1),
 #if defined(__arm__)
-  ELFW(SYM_INITIALIZER)(271, &dl_unwind_find_exidx, 1),
+  ELFW(SYM_INITIALIZER)(265, &dl_unwind_find_exidx, 1),
 #endif
 };
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 1ecf65b..9780231 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -111,6 +111,7 @@
 };
 
 android_namespace_t g_default_namespace;
+android_namespace_t* g_anonymous_namespace = &g_default_namespace;
 
 static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
 
@@ -2201,7 +2202,7 @@
     return nullptr;
   }
 
-  android_namespace_t* ns = caller->get_namespace();
+  android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
 
   if (extinfo != nullptr) {
     if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
@@ -2246,14 +2247,14 @@
   soinfo_unload(si);
 }
 
-bool init_public_namespace(const char* libs) {
-  CHECK(libs != nullptr);
+bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
+  CHECK(public_ns_sonames != nullptr);
   if (g_public_namespace_initialized) {
-    DL_ERR("Public namespace has already been initialized.");
+    DL_ERR("public namespace has already been initialized.");
     return false;
   }
 
-  std::vector<std::string> sonames = android::base::Split(libs, ":");
+  std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
 
   ProtectedDataGuard guard;
 
@@ -2267,7 +2268,7 @@
     find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
 
     if (candidate == nullptr) {
-      DL_ERR("Error initializing public namespace: \"%s\" was not found"
+      DL_ERR("error initializing public namespace: \"%s\" was not found"
              " in the default namespace", soname.c_str());
       return false;
     }
@@ -2276,8 +2277,18 @@
     g_public_namespace.push_back(candidate);
   }
 
-  failure_guard.disable();
   g_public_namespace_initialized = true;
+
+  // create anonymous namespace
+  android_namespace_t* anon_ns =
+      create_namespace("(anonymous)", nullptr, anon_ns_library_path, false);
+
+  if (anon_ns == nullptr) {
+    g_public_namespace_initialized = false;
+    return false;
+  }
+  g_anonymous_namespace = anon_ns;
+  failure_guard.disable();
   return true;
 }
 
@@ -2286,7 +2297,7 @@
                                       const char* default_library_path,
                                       bool is_isolated) {
   if (!g_public_namespace_initialized) {
-    DL_ERR("Cannot create namespace: public namespace is not initialized.");
+    DL_ERR("cannot create namespace: public namespace is not initialized.");
     return nullptr;
   }
 
diff --git a/linker/linker.h b/linker/linker.h
index c46b4e1..b391fc3 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -444,7 +444,7 @@
 void set_application_target_sdk_version(uint32_t target);
 uint32_t get_application_target_sdk_version();
 
-bool init_public_namespace(const char* path);
+bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path);
 android_namespace_t* create_namespace(const char* name, const char* ld_library_path,
                                       const char* default_library_path, bool is_isolated);
 
diff --git a/linker/linker_mapped_file_fragment.cpp b/linker/linker_mapped_file_fragment.cpp
index 6a500ef..27c1c69 100644
--- a/linker/linker_mapped_file_fragment.cpp
+++ b/linker/linker_mapped_file_fragment.cpp
@@ -16,32 +16,13 @@
 
 #include "linker_mapped_file_fragment.h"
 #include "linker_debug.h"
+#include "linker_utils.h"
 
 #include <inttypes.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <unistd.h>
 
-constexpr off64_t kPageMask = ~static_cast<off64_t>(PAGE_SIZE-1);
-
-static off64_t page_start(off64_t offset) {
-  return offset & kPageMask;
-}
-
-static bool safe_add(off64_t* out, off64_t a, size_t b) {
-  CHECK(a >= 0);
-  if (static_cast<uint64_t>(INT64_MAX - a) < b) {
-    return false;
-  }
-
-  *out = a + b;
-  return true;
-}
-
-static size_t page_offset(off64_t offset) {
-  return static_cast<size_t>(offset & (PAGE_SIZE-1));
-}
-
 MappedFileFragment::MappedFileFragment() : map_start_(nullptr), map_size_(0),
                                            data_(nullptr), size_ (0)
 { }
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 347983e..4c4ce17 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -37,6 +37,7 @@
 
 #include "linker.h"
 #include "linker_debug.h"
+#include "linker_utils.h"
 
 static int GetTargetElfMachine() {
 #if defined(__arm__)
@@ -244,6 +245,16 @@
   return true;
 }
 
+bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size) {
+  off64_t range_start;
+  off64_t range_end;
+
+  return safe_add(&range_start, file_offset_, offset) &&
+         safe_add(&range_end, range_start, size) &&
+         range_start < file_size_ &&
+         range_end <= file_size_;
+}
+
 // Loads the program header table from an ELF file into a read-only private
 // anonymous mmap-ed block.
 bool ElfReader::ReadProgramHeaders() {
@@ -256,7 +267,14 @@
     return false;
   }
 
-  if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, phdr_num_ * sizeof(ElfW(Phdr)))) {
+  // Boundary checks
+  size_t size = phdr_num_ * sizeof(ElfW(Phdr));
+  if (!CheckFileRange(header_.e_phoff, size)) {
+    DL_ERR("\"%s\" has invalid phdr offset/size", name_.c_str());
+    return false;
+  }
+
+  if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, size)) {
     DL_ERR("\"%s\" phdr mmap failed: %s", name_.c_str(), strerror(errno));
     return false;
   }
@@ -268,7 +286,18 @@
 bool ElfReader::ReadSectionHeaders() {
   shdr_num_ = header_.e_shnum;
 
-  if (!shdr_fragment_.Map(fd_, file_offset_, header_.e_shoff, shdr_num_ * sizeof(ElfW(Shdr)))) {
+  if (shdr_num_ == 0) {
+    DL_ERR("\"%s\" has no section headers", name_.c_str());
+    return false;
+  }
+
+  size_t size = shdr_num_ * sizeof(ElfW(Shdr));
+  if (!CheckFileRange(header_.e_shoff, size)) {
+    DL_ERR("\"%s\" has invalid shdr offset/size", name_.c_str());
+    return false;
+  }
+
+  if (!shdr_fragment_.Map(fd_, file_offset_, header_.e_shoff, size)) {
     DL_ERR("\"%s\" shdr mmap failed: %s", name_.c_str(), strerror(errno));
     return false;
   }
@@ -288,7 +317,7 @@
   }
 
   if (dynamic_shdr == nullptr) {
-    DL_ERR("\"%s\" .dynamic section was not found", name_.c_str());
+    DL_ERR("\"%s\" .dynamic section header was not found", name_.c_str());
     return false;
   }
 
@@ -305,6 +334,12 @@
     return false;
   }
 
+  if (!CheckFileRange(dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
+    DL_ERR("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
+    PRINT("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
+    return false;
+  }
+
   if (!dynamic_fragment_.Map(fd_, file_offset_, dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
     DL_ERR("\"%s\" dynamic section mmap failed: %s", name_.c_str(), strerror(errno));
     return false;
@@ -312,6 +347,12 @@
 
   dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_fragment_.data());
 
+  if (!CheckFileRange(strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
+    DL_ERR("\"%s\" has invalid offset/size of the .strtab section linked from .dynamic section",
+           name_.c_str());
+    return false;
+  }
+
   if (!strtab_fragment_.Map(fd_, file_offset_, strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
     DL_ERR("\"%s\" strtab section mmap failed: %s", name_.c_str(), strerror(errno));
     return false;
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index f7b1caf..c359cca 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -64,6 +64,7 @@
   bool LoadSegments();
   bool FindPhdr();
   bool CheckPhdr(ElfW(Addr));
+  bool CheckFileRange(ElfW(Addr) offset, size_t size);
 
   bool did_read_;
   bool did_load_;
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index f81b77b..db43d38 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -105,3 +105,23 @@
   return true;
 }
 
+constexpr off64_t kPageMask = ~static_cast<off64_t>(PAGE_SIZE-1);
+
+off64_t page_start(off64_t offset) {
+  return offset & kPageMask;
+}
+
+bool safe_add(off64_t* out, off64_t a, size_t b) {
+  CHECK(a >= 0);
+  if (static_cast<uint64_t>(INT64_MAX - a) < b) {
+    return false;
+  }
+
+  *out = a + b;
+  return true;
+}
+
+size_t page_offset(off64_t offset) {
+  return static_cast<size_t>(offset & (PAGE_SIZE-1));
+}
+
diff --git a/linker/linker_utils.h b/linker/linker_utils.h
index b998fb5..65ffbdc5 100644
--- a/linker/linker_utils.h
+++ b/linker/linker_utils.h
@@ -24,4 +24,8 @@
 bool file_is_in_dir(const std::string& file, const std::string& dir);
 bool parse_zip_path(const char* input_path, std::string* zip_path, std::string* entry_path);
 
+off64_t page_start(off64_t offset);
+size_t page_offset(off64_t offset);
+bool safe_add(off64_t* out, off64_t a, size_t b);
+
 #endif
diff --git a/linker/tests/linker_utils_test.cpp b/linker/tests/linker_utils_test.cpp
index d9b290c..3be9b3f 100644
--- a/linker/tests/linker_utils_test.cpp
+++ b/linker/tests/linker_utils_test.cpp
@@ -69,3 +69,24 @@
   ASSERT_EQ("", entry_path);
 }
 
+TEST(linker_utils, page_start) {
+  ASSERT_EQ(0x0001000, page_start(0x0001000));
+  ASSERT_EQ(0x3002000, page_start(0x300222f));
+  ASSERT_EQ(0x6001000, page_start(0x6001fff));
+}
+
+TEST(linker_utils, page_offset) {
+  ASSERT_EQ(0x0U, page_offset(0x0001000));
+  ASSERT_EQ(0x22fU, page_offset(0x300222f));
+  ASSERT_EQ(0xfffU, page_offset(0x6001fff));
+}
+
+TEST(linker_utils, safe_add) {
+  int64_t val = 42;
+  ASSERT_FALSE(safe_add(&val, INT64_MAX-20, 21U));
+  ASSERT_EQ(42, val);
+  ASSERT_TRUE(safe_add(&val, INT64_MAX-42, 42U));
+  ASSERT_EQ(INT64_MAX, val);
+  ASSERT_TRUE(safe_add(&val, 2000, 42U));
+  ASSERT_EQ(2042, val);
+}
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index a56c771..83791eb 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -32,6 +32,7 @@
 #include <pagemap/pagemap.h>
 
 #include "TemporaryFile.h"
+#include "utils.h"
 
 #define ASSERT_DL_NOTNULL(ptr) \
     ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror()
@@ -610,8 +611,8 @@
   static const char* root_lib = "libnstest_root.so";
   std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
 
-  ASSERT_FALSE(android_init_public_namespace(path.c_str()));
-  ASSERT_STREQ("android_init_public_namespace failed: Error initializing public namespace: "
+  ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr));
+  ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
                "\"libnstest_public.so\" was not found in the default namespace", dlerror());
 
   const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
@@ -619,7 +620,7 @@
   void* handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), RTLD_NOW);
   ASSERT_TRUE(handle_public != nullptr) << dlerror();
 
-  ASSERT_TRUE(android_init_public_namespace(path.c_str())) << dlerror();
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
 
   // Check that libraries added to public namespace are NODELETE
   dlclose(handle_public);
@@ -719,7 +720,7 @@
 
   android_set_application_target_sdk_version(42U); // something > 23
 
-  ASSERT_TRUE(android_init_public_namespace(path.c_str())) << dlerror();
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
 
   android_namespace_t* ns_not_isolated = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false);
   ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
@@ -795,3 +796,94 @@
 
   dlclose(handle1);
 }
+
+TEST(dlext, ns_anonymous) {
+  static const char* root_lib = "libnstest_root.so";
+  std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
+
+  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
+
+  void* handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(),
+                               RTLD_NOW);
+  ASSERT_TRUE(handle_public != nullptr) << dlerror();
+
+  ASSERT_TRUE(android_init_namespaces(path.c_str(), (lib_path + "/private_namespace_libs").c_str()))
+      << dlerror();
+
+  android_namespace_t* ns = android_create_namespace(
+                                "private", nullptr,
+                                (lib_path + "/private_namespace_libs").c_str(),
+                                false);
+
+  ASSERT_TRUE(ns != nullptr) << dlerror();
+
+  std::string private_library_absolute_path = lib_path + "/private_namespace_libs/" + root_lib;
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns;
+
+  // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string
+  void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  uintptr_t ns_get_dlopened_string_addr =
+      reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string"));
+  ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror();
+  typedef const char* (*fn_t)();
+  fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr);
+
+  std::vector<map_record> maps;
+  Maps::parse_maps(&maps);
+
+  uintptr_t addr_start = 0;
+  uintptr_t addr_end = 0;
+  std::vector<map_record> maps_to_copy;
+
+  for (const auto& rec : maps) {
+    if (rec.pathname == private_library_absolute_path) {
+      if (addr_start == 0) {
+        addr_start = rec.addr_start;
+      }
+      addr_end = rec.addr_end;
+
+      maps_to_copy.push_back(rec);
+    }
+  }
+
+  // some sanity checks..
+  ASSERT_TRUE(addr_start > 0);
+  ASSERT_TRUE(addr_end > 0);
+  ASSERT_EQ(3U, maps_to_copy.size());
+  ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start);
+  ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end);
+
+  // copy
+  uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start,
+                                                             PROT_NONE, MAP_ANON | MAP_PRIVATE,
+                                                             -1, 0));
+  ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED);
+
+  for (const auto& rec : maps_to_copy) {
+    uintptr_t offset = rec.addr_start - addr_start;
+    size_t size = rec.addr_end - rec.addr_start;
+    void* addr = reinterpret_cast<void*>(reserved_addr + offset);
+    void* map = mmap(addr, size, PROT_READ | PROT_WRITE,
+                     MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
+    ASSERT_TRUE(map != MAP_FAILED);
+    memcpy(map, reinterpret_cast<void*>(rec.addr_start), size);
+    mprotect(map, size, rec.perms);
+  }
+
+  // call the function copy
+  uintptr_t ns_get_dlopened_string_offset  = ns_get_dlopened_string_addr - addr_start;
+  fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset);
+  ASSERT_STREQ("This string is from private namespace (dlopened library)",
+               ns_get_dlopened_string_anon());
+
+  // They should belong to different namespaces (private and anonymous)
+  ASSERT_STREQ("This string is from private namespace (dlopened library)",
+               ns_get_dlopened_string_private());
+
+  ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private());
+}
diff --git a/tests/libs/namespaces_root.cpp b/tests/libs/namespaces_root.cpp
index 0bb4611..b0006c7 100644
--- a/tests/libs/namespaces_root.cpp
+++ b/tests/libs/namespaces_root.cpp
@@ -40,10 +40,12 @@
     return nullptr;
   }
 
-  const char* result = *static_cast<const char**>(dlsym(handle, "g_private_dlopened_string"));
-  if (result != nullptr) {
+  const char** result = static_cast<const char**>(dlsym(handle, "g_private_dlopened_string"));
+  if (result == nullptr) {
+    return nullptr;
+  } else {
     g_dlopened = true;
   }
 
-  return result;
+  return *result;
 }
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index e237d26..f6d3501 100755
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -30,12 +30,9 @@
 #include <unwind.h>
 
 #include <atomic>
-#include <regex>
 #include <vector>
 
-#include <base/file.h>
-#include <base/stringprintf.h>
-
+#include "private/bionic_constants.h"
 #include "private/bionic_macros.h"
 #include "private/ScopeGuard.h"
 #include "BionicDeathTest.h"
@@ -43,8 +40,6 @@
 
 #include "utils.h"
 
-extern "C" pid_t gettid();
-
 TEST(pthread, pthread_key_create) {
   pthread_key_t key;
   ASSERT_EQ(0, pthread_key_create(&key, NULL));
@@ -721,58 +716,47 @@
   ASSERT_EQ(0, pthread_rwlock_destroy(&l));
 }
 
-static void WaitUntilThreadSleep(std::atomic<pid_t>& tid) {
-  while (tid == 0) {
-    usleep(1000);
-  }
-  std::string filename = android::base::StringPrintf("/proc/%d/stat", tid.load());
-  std::regex regex {R"(\s+S\s+)"};
-
-  while (true) {
-    std::string content;
-    ASSERT_TRUE(android::base::ReadFileToString(filename, &content));
-    if (std::regex_search(content, regex)) {
-      break;
-    }
-    usleep(1000);
-  }
-}
-
 struct RwlockWakeupHelperArg {
   pthread_rwlock_t lock;
   enum Progress {
     LOCK_INITIALIZED,
     LOCK_WAITING,
     LOCK_RELEASED,
-    LOCK_ACCESSED
+    LOCK_ACCESSED,
+    LOCK_TIMEDOUT,
   };
   std::atomic<Progress> progress;
   std::atomic<pid_t> tid;
+  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;
 };
 
-static void pthread_rwlock_reader_wakeup_writer_helper(RwlockWakeupHelperArg* arg) {
+static void pthread_rwlock_wakeup_helper(RwlockWakeupHelperArg* arg) {
   arg->tid = gettid();
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
   arg->progress = RwlockWakeupHelperArg::LOCK_WAITING;
 
-  ASSERT_EQ(EBUSY, pthread_rwlock_trywrlock(&arg->lock));
-  ASSERT_EQ(0, pthread_rwlock_wrlock(&arg->lock));
+  ASSERT_EQ(EBUSY, arg->trylock_function(&arg->lock));
+  ASSERT_EQ(0, arg->lock_function(&arg->lock));
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_RELEASED, arg->progress);
   ASSERT_EQ(0, pthread_rwlock_unlock(&arg->lock));
 
   arg->progress = RwlockWakeupHelperArg::LOCK_ACCESSED;
 }
 
-TEST(pthread, pthread_rwlock_reader_wakeup_writer) {
+static void test_pthread_rwlock_reader_wakeup_writer(std::function<int (pthread_rwlock_t*)> lock_function) {
   RwlockWakeupHelperArg wakeup_arg;
   ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, NULL));
   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.lock_function = lock_function;
 
   pthread_t thread;
   ASSERT_EQ(0, pthread_create(&thread, NULL,
-    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_reader_wakeup_writer_helper), &wakeup_arg));
+    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_helper), &wakeup_arg));
   WaitUntilThreadSleep(wakeup_arg.tid);
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
 
@@ -784,29 +768,31 @@
   ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
 }
 
-static void pthread_rwlock_writer_wakeup_reader_helper(RwlockWakeupHelperArg* arg) {
-  arg->tid = gettid();
-  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
-  arg->progress = RwlockWakeupHelperArg::LOCK_WAITING;
-
-  ASSERT_EQ(EBUSY, pthread_rwlock_tryrdlock(&arg->lock));
-  ASSERT_EQ(0, pthread_rwlock_rdlock(&arg->lock));
-  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_RELEASED, arg->progress);
-  ASSERT_EQ(0, pthread_rwlock_unlock(&arg->lock));
-
-  arg->progress = RwlockWakeupHelperArg::LOCK_ACCESSED;
+TEST(pthread, pthread_rwlock_reader_wakeup_writer) {
+  test_pthread_rwlock_reader_wakeup_writer(pthread_rwlock_wrlock);
 }
 
-TEST(pthread, pthread_rwlock_writer_wakeup_reader) {
+TEST(pthread, pthread_rwlock_reader_wakeup_writer_timedwait) {
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ts.tv_sec += 1;
+  test_pthread_rwlock_reader_wakeup_writer([&](pthread_rwlock_t* lock) {
+    return pthread_rwlock_timedwrlock(lock, &ts);
+  });
+}
+
+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));
   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.lock_function = lock_function;
 
   pthread_t thread;
   ASSERT_EQ(0, pthread_create(&thread, NULL,
-    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_writer_wakeup_reader_helper), &wakeup_arg));
+    reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_helper), &wakeup_arg));
   WaitUntilThreadSleep(wakeup_arg.tid);
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
 
@@ -818,6 +804,85 @@
   ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
 }
 
+TEST(pthread, pthread_rwlock_writer_wakeup_reader) {
+  test_pthread_rwlock_writer_wakeup_reader(pthread_rwlock_rdlock);
+}
+
+TEST(pthread, pthread_rwlock_writer_wakeup_reader_timedwait) {
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ts.tv_sec += 1;
+  test_pthread_rwlock_writer_wakeup_reader([&](pthread_rwlock_t* lock) {
+    return pthread_rwlock_timedrdlock(lock, &ts);
+  });
+}
+
+static void pthread_rwlock_wakeup_timeout_helper(RwlockWakeupHelperArg* arg) {
+  arg->tid = gettid();
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
+  arg->progress = RwlockWakeupHelperArg::LOCK_WAITING;
+
+  ASSERT_EQ(EBUSY, arg->trylock_function(&arg->lock));
+
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &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));
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(EINVAL, arg->timed_lock_function(&arg->lock, &ts));
+  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));
+  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) {
+  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;
+
+  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_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_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));
+}
+
 class RwlockKindTestHelper {
  private:
   struct ThreadArg {
@@ -1062,36 +1127,44 @@
   };
   std::atomic<Progress> progress;
   pthread_t thread;
+  std::function<int (pthread_cond_t* cond, pthread_mutex_t* mutex)> wait_function;
 
  protected:
-  virtual void SetUp() {
-    ASSERT_EQ(0, pthread_mutex_init(&mutex, NULL));
-    ASSERT_EQ(0, pthread_cond_init(&cond, NULL));
+  void SetUp() override {
+    ASSERT_EQ(0, pthread_mutex_init(&mutex, nullptr));
+  }
+
+  void InitCond(clockid_t clock=CLOCK_REALTIME) {
+    pthread_condattr_t attr;
+    ASSERT_EQ(0, pthread_condattr_init(&attr));
+    ASSERT_EQ(0, pthread_condattr_setclock(&attr, clock));
+    ASSERT_EQ(0, pthread_cond_init(&cond, &attr));
+    ASSERT_EQ(0, pthread_condattr_destroy(&attr));
+  }
+
+  void StartWaitingThread(std::function<int (pthread_cond_t* cond, pthread_mutex_t* mutex)> wait_function) {
     progress = INITIALIZED;
-    ASSERT_EQ(0,
-      pthread_create(&thread, NULL, reinterpret_cast<void* (*)(void*)>(WaitThreadFn), this));
-  }
-
-  virtual void TearDown() {
-    ASSERT_EQ(0, pthread_join(thread, NULL));
-    ASSERT_EQ(FINISHED, progress);
-    ASSERT_EQ(0, pthread_cond_destroy(&cond));
-    ASSERT_EQ(0, pthread_mutex_destroy(&mutex));
-  }
-
-  void SleepUntilProgress(Progress expected_progress) {
-    while (progress != expected_progress) {
+    this->wait_function = wait_function;
+    ASSERT_EQ(0, pthread_create(&thread, NULL, reinterpret_cast<void* (*)(void*)>(WaitThreadFn), this));
+    while (progress != WAITING) {
       usleep(5000);
     }
     usleep(5000);
   }
 
+  void TearDown() override {
+    ASSERT_EQ(0, pthread_join(thread, nullptr));
+    ASSERT_EQ(FINISHED, progress);
+    ASSERT_EQ(0, pthread_cond_destroy(&cond));
+    ASSERT_EQ(0, pthread_mutex_destroy(&mutex));
+  }
+
  private:
   static void WaitThreadFn(pthread_CondWakeupTest* test) {
     ASSERT_EQ(0, pthread_mutex_lock(&test->mutex));
     test->progress = WAITING;
     while (test->progress == WAITING) {
-      ASSERT_EQ(0, pthread_cond_wait(&test->cond, &test->mutex));
+      ASSERT_EQ(0, test->wait_function(&test->cond, &test->mutex));
     }
     ASSERT_EQ(SIGNALED, test->progress);
     test->progress = FINISHED;
@@ -1099,39 +1172,65 @@
   }
 };
 
-TEST_F(pthread_CondWakeupTest, signal) {
-  SleepUntilProgress(WAITING);
+TEST_F(pthread_CondWakeupTest, signal_wait) {
+  InitCond();
+  StartWaitingThread([](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_wait(cond, mutex);
+  });
   progress = SIGNALED;
-  pthread_cond_signal(&cond);
+  ASSERT_EQ(0, pthread_cond_signal(&cond));
 }
 
-TEST_F(pthread_CondWakeupTest, broadcast) {
-  SleepUntilProgress(WAITING);
+TEST_F(pthread_CondWakeupTest, broadcast_wait) {
+  InitCond();
+  StartWaitingThread([](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_wait(cond, mutex);
+  });
   progress = SIGNALED;
-  pthread_cond_broadcast(&cond);
+  ASSERT_EQ(0, pthread_cond_broadcast(&cond));
 }
 
-TEST(pthread, pthread_mutex_timedlock) {
-  pthread_mutex_t m;
-  ASSERT_EQ(0, pthread_mutex_init(&m, NULL));
-
-  // If the mutex is already locked, pthread_mutex_timedlock should time out.
-  ASSERT_EQ(0, pthread_mutex_lock(&m));
-
+TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_REALTIME) {
+  InitCond(CLOCK_REALTIME);
   timespec ts;
   ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
-  ts.tv_nsec += 1;
-  ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_sec += 1;
+  StartWaitingThread([&](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_timedwait(cond, mutex, &ts);
+  });
+  progress = SIGNALED;
+  ASSERT_EQ(0, pthread_cond_signal(&cond));
+}
 
-  // If the mutex is unlocked, pthread_mutex_timedlock should succeed.
-  ASSERT_EQ(0, pthread_mutex_unlock(&m));
+TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_MONOTONIC) {
+  InitCond(CLOCK_MONOTONIC);
+  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(cond, mutex, &ts);
+  });
+  progress = SIGNALED;
+  ASSERT_EQ(0, pthread_cond_signal(&cond));
+}
 
+TEST(pthread, pthread_cond_timedwait_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));
-  ts.tv_nsec += 1;
-  ASSERT_EQ(0, pthread_mutex_timedlock(&m, &ts));
-
-  ASSERT_EQ(0, pthread_mutex_unlock(&m));
-  ASSERT_EQ(0, pthread_mutex_destroy(&m));
+  ASSERT_EQ(ETIMEDOUT, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ts.tv_nsec = -1;
+  ASSERT_EQ(EINVAL, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(EINVAL, pthread_cond_timedwait(&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(0, pthread_mutex_unlock(&mutex));
 }
 
 TEST(pthread, pthread_attr_getstack__main_thread) {
@@ -1552,6 +1651,35 @@
 #endif
 }
 
+TEST(pthread, pthread_mutex_timedlock) {
+  pthread_mutex_t m;
+  ASSERT_EQ(0, pthread_mutex_init(&m, nullptr));
+
+  // If the mutex is already locked, pthread_mutex_timedlock should time out.
+  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));
+  ts.tv_nsec = -1;
+  ASSERT_EQ(EINVAL, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(EINVAL, pthread_mutex_timedlock(&m, &ts));
+  ts.tv_nsec = NS_PER_S - 1;
+  ts.tv_sec = -1;
+  ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&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));
+  ts.tv_sec += 1;
+  ASSERT_EQ(0, pthread_mutex_timedlock(&m, &ts));
+
+  ASSERT_EQ(0, pthread_mutex_unlock(&m));
+  ASSERT_EQ(0, pthread_mutex_destroy(&m));
+}
+
 class StrictAlignmentAllocator {
  public:
   void* allocate(size_t size, size_t alignment) {
@@ -1749,13 +1877,13 @@
   const size_t ITERATION_COUNT = 10000;
   for (size_t i = 1; i <= ITERATION_COUNT; ++i) {
     arg->array[arg->id] = i;
-    int ret = pthread_barrier_wait(arg->barrier);
-    ASSERT_TRUE(ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD);
+    int result = pthread_barrier_wait(arg->barrier);
+    ASSERT_TRUE(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD);
     for (size_t j = 0; j < arg->array_length; ++j) {
       ASSERT_EQ(i, arg->array[j]);
     }
-    ret = pthread_barrier_wait(arg->barrier);
-    ASSERT_TRUE(ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD);
+    result = pthread_barrier_wait(arg->barrier);
+    ASSERT_TRUE(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD);
   }
 }
 
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index e517f81..b65bfb8 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -117,6 +117,16 @@
   ts.tv_nsec = -1;
   ASSERT_EQ(-1, sem_timedwait(&s, &ts));
   ASSERT_EQ(EINVAL, errno);
+  errno = 0;
+  ts.tv_nsec = NS_PER_S;
+  ASSERT_EQ(-1, sem_timedwait(&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(ETIMEDOUT, errno);
 
   ASSERT_EQ(0, sem_destroy(&s));
 }
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
index c95cbbd..7872567 100644
--- a/tests/stdio_ext_test.cpp
+++ b/tests/stdio_ext_test.cpp
@@ -30,6 +30,7 @@
 #include <locale.h>
 
 #include "TemporaryFile.h"
+#include "utils.h"
 
 TEST(stdio_ext, __fbufsize) {
   FILE* fp = fopen("/proc/version", "r");
@@ -140,3 +141,24 @@
   ASSERT_EQ(FSETLOCKING_INTERNAL, __fsetlocking(fp, FSETLOCKING_QUERY));
   fclose(fp);
 }
+
+static void LockingByCallerHelper(std::atomic<pid_t>* pid) {
+  *pid = gettid();
+  flockfile(stdout);
+  funlockfile(stdout);
+}
+
+TEST(stdio_ext, __fsetlocking_BYCALLER) {
+  // Check if users can use flockfile/funlockfile to protect stdio operations.
+  int old_state = __fsetlocking(stdout, FSETLOCKING_BYCALLER);
+  flockfile(stdout);
+  pthread_t thread;
+  std::atomic<pid_t> pid(0);
+  ASSERT_EQ(0, pthread_create(&thread, nullptr,
+                              reinterpret_cast<void* (*)(void*)>(LockingByCallerHelper), &pid));
+  WaitUntilThreadSleep(pid);
+  funlockfile(stdout);
+
+  ASSERT_EQ(0, pthread_join(thread, nullptr));
+  __fsetlocking(stdout, old_state);
+}
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index dffb646..ddb6c77 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include <sys/mman.h>
+#include <sys/user.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -219,3 +220,15 @@
 TEST(sys_mman, mremap) {
   ASSERT_EQ(MAP_FAILED, mremap(nullptr, 0, 0, 0));
 }
+
+const size_t huge = size_t(PTRDIFF_MAX) + 1;
+
+TEST(sys_mman, mmap_PTRDIFF_MAX) {
+  ASSERT_EQ(MAP_FAILED, mmap(nullptr, huge, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+}
+
+TEST(sys_mman, mremap_PTRDIFF_MAX) {
+  void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  ASSERT_NE(MAP_FAILED, map);
+  ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, huge, MREMAP_MAYMOVE));
+}
diff --git a/tests/utils.h b/tests/utils.h
index 53cf6b6..9e77f24 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -18,6 +18,14 @@
 #define __TEST_UTILS_H
 #include <inttypes.h>
 #include <sys/mman.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <string>
+#include <regex>
+
+#include <base/file.h>
+#include <base/stringprintf.h>
 
 #include "private/ScopeGuard.h"
 
@@ -82,4 +90,23 @@
   }
 };
 
+extern "C" pid_t gettid();
+
+static inline void WaitUntilThreadSleep(std::atomic<pid_t>& tid) {
+  while (tid == 0) {
+    usleep(1000);
+  }
+  std::string filename = android::base::StringPrintf("/proc/%d/stat", tid.load());
+  std::regex regex {R"(\s+S\s+)"};
+
+  while (true) {
+    std::string content;
+    ASSERT_TRUE(android::base::ReadFileToString(filename, &content));
+    if (std::regex_search(content, regex)) {
+      break;
+    }
+    usleep(1000);
+  }
+}
+
 #endif