Merge "libc fortify: make string.h use diagnose_if"
diff --git a/libc/include/bits/fortify/fcntl.h b/libc/include/bits/fortify/fcntl.h
index 1d3d7bc..3e0a590 100644
--- a/libc/include/bits/fortify/fcntl.h
+++ b/libc/include/bits/fortify/fcntl.h
@@ -48,11 +48,6 @@
 int open(const char* pathname, int flags, mode_t modes, ...) __overloadable
         __errorattr(__open_too_many_args_error);
 
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-int open(const char* pathname, int flags) __overloadable
-        __enable_if(flags & O_CREAT, __open_too_few_args_error)
-        __errorattr(__open_too_few_args_error);
-
 /*
  * pass_object_size serves two purposes here, neither of which involve __bos: it
  * disqualifies this function from having its address taken (so &open works),
@@ -60,30 +55,27 @@
  * open(const char *, int, ...).
  */
 __BIONIC_FORTIFY_INLINE
-int open(const char* const __pass_object_size pathname,
-         int flags) __overloadable {
+int open(const char* const __pass_object_size pathname, int flags)
+        __overloadable
+        __clang_error_if(flags & O_CREAT, "'open' " __open_too_few_args_error) {
     return __open_2(pathname, flags);
 }
 
 __BIONIC_FORTIFY_INLINE
-int open(const char* const __pass_object_size pathname, int flags, mode_t modes)
-        __overloadable {
+int open(const char* const __pass_object_size pathname, int flags, mode_t modes) __overloadable {
     return __open_real(pathname, flags, modes);
 }
 
 __BIONIC_ERROR_FUNCTION_VISIBILITY
-int openat(int dirfd, const char* pathname, int flags) __overloadable
-        __enable_if(flags & O_CREAT, __open_too_few_args_error)
-        __errorattr(__open_too_few_args_error);
-
-__BIONIC_ERROR_FUNCTION_VISIBILITY
 int openat(int dirfd, const char* pathname, int flags, mode_t modes, ...)
         __overloadable
         __errorattr(__open_too_many_args_error);
 
 __BIONIC_FORTIFY_INLINE
 int openat(int dirfd, const char* const __pass_object_size pathname,
-           int flags) __overloadable {
+           int flags)
+        __overloadable
+        __clang_error_if(flags & O_CREAT, "'openat' " __open_too_few_args_error) {
     return __openat_2(dirfd, pathname, flags);
 }
 
diff --git a/libc/include/bits/fortify/poll.h b/libc/include/bits/fortify/poll.h
index e9b52c8..8363e35 100644
--- a/libc/include/bits/fortify/poll.h
+++ b/libc/include/bits/fortify/poll.h
@@ -37,42 +37,31 @@
 #if defined(__BIONIC_FORTIFY)
 #if __ANDROID_API__ >= __ANDROID_API_M__
 #if defined(__clang__)
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-int poll(struct pollfd* fds, nfds_t fd_count, int timeout) __overloadable
-        __enable_if(__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
-                    __bos(fds) < sizeof(*fds) * fd_count,
-                    "selected when there aren't fd_count fds")
-        __errorattr("too many fds specified");
-
 __BIONIC_FORTIFY_INLINE
-int poll(struct pollfd* const fds __pass_object_size, nfds_t fd_count,
-        int timeout) __overloadable {
+int poll(struct pollfd* const fds __pass_object_size, nfds_t fd_count, int timeout)
+    __overloadable
+    __clang_error_if(__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+                       __bos(fds) < sizeof(*fds) * fd_count,
+                     "in call to 'poll', 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(poll)(fds, fd_count, timeout);
+    return __call_bypassing_fortify(poll)(fds, fd_count, timeout);
   }
-
   return __poll_chk(fds, fd_count, timeout, bos_fds);
 }
 
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-int ppoll(struct pollfd* fds, nfds_t fd_count, const struct timespec* timeout,
-          const sigset_t* mask)  __overloadable
-        __enable_if(__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
-                    __bos(fds) < sizeof(*fds) * fd_count,
-                    "selected when there aren't fd_count fds")
-        __errorattr("too many fds specified");
-
 __BIONIC_FORTIFY_INLINE
-int ppoll(struct pollfd* const fds __pass_object_size, nfds_t fd_count,
-          const struct timespec* timeout, const sigset_t* mask) __overloadable {
+int ppoll(struct pollfd* const fds __pass_object_size, nfds_t fd_count, const struct timespec* timeout, const sigset_t* mask)
+    __overloadable
+    __clang_error_if(__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+                       __bos(fds) < sizeof(*fds) * fd_count,
+                     "in call to 'ppoll', 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(ppoll)(fds, fd_count, timeout, mask);
+    return __call_bypassing_fortify(ppoll)(fds, fd_count, timeout, mask);
   }
-
   return __ppoll_chk(fds, fd_count, timeout, mask, bos_fds);
 }
 #else /* defined(__clang__) */
diff --git a/libc/include/bits/fortify/socket.h b/libc/include/bits/fortify/socket.h
index c9e9436..3e610d6 100644
--- a/libc/include/bits/fortify/socket.h
+++ b/libc/include/bits/fortify/socket.h
@@ -37,64 +37,55 @@
 
 #if defined(__BIONIC_FORTIFY)
 
-#define __recvfrom_bad_size "recvfrom called with size bigger than buffer"
-#define __sendto_bad_size "sendto called with size bigger than buffer"
+#define __recvfrom_bad_size "'recvfrom' called with size bigger than buffer"
+#define __sendto_bad_size "'sendto' called with size bigger than buffer"
 #if defined(__clang__)
 #if __ANDROID_API__ >= __ANDROID_API_N__
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-ssize_t recvfrom(int fd, void* const buf __pass_object_size0, size_t len,
-                 int flags, struct sockaddr* src_addr, socklen_t* addr_len)
-        __overloadable
-        __enable_if(__bos(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
-                    __bos(buf) < len, "selected when the buffer is too small")
-        __errorattr(__recvfrom_bad_size);
-
 __BIONIC_FORTIFY_INLINE
-ssize_t recvfrom(int fd, void* const buf __pass_object_size0, size_t len,
-                 int flags, struct sockaddr* src_addr, socklen_t* addr_len)
-      __overloadable {
+ssize_t recvfrom(int fd, void* const buf __pass_object_size0, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addr_len)
+    __overloadable
+    __clang_error_if(__bos(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE && __bos(buf) < len,
+                     __recvfrom_bad_size) {
   size_t bos = __bos0(buf);
 
   if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
-    return __call_bypassing_fortify(recvfrom)(fd, buf, len, flags, src_addr,
-              addr_len);
+    return __call_bypassing_fortify(recvfrom)(fd, buf, len, flags, src_addr, addr_len);
   }
-
   return __recvfrom_chk(fd, buf, len, bos, flags, src_addr, addr_len);
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
 
 #if __ANDROID_API__ >= __ANDROID_API_N_MR1__
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-ssize_t sendto(int fd, const void* buf, size_t len, int flags,
-               const struct sockaddr* dest_addr, socklen_t addr_len)
-        __overloadable
-        __enable_if(__bos0(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
-                    __bos0(buf) < len, "selected when the buffer is too small")
-        __errorattr(__sendto_bad_size);
-
 __BIONIC_FORTIFY_INLINE
-ssize_t sendto(int fd, const void* const buf __pass_object_size0, size_t len,
-               int flags, const struct sockaddr* dest_addr, socklen_t addr_len)
-      __overloadable {
+ssize_t sendto(int fd, const void* const buf __pass_object_size0, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addr_len)
+    __overloadable
+    __clang_error_if(__bos0(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE && __bos0(buf) < len,
+                     __sendto_bad_size) {
   size_t bos = __bos0(buf);
 
   if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
-    return __call_bypassing_fortify(sendto)(fd, buf, len, flags, dest_addr,
-              addr_len);
+    return __call_bypassing_fortify(sendto)(fd, buf, len, flags, dest_addr, addr_len);
   }
-
   return __sendto_chk(fd, buf, len, bos, flags, dest_addr, addr_len);
 }
-
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-ssize_t send(int socket, const void* buf, size_t len, int flags)
-        __overloadable
-        __enable_if(__bos0(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
-                    __bos0(buf) < len, "selected when the buffer is too small")
-        __errorattr("send called with size bigger than buffer");
 #endif /* __ANDROID_API__ >= __ANDROID_API_N_MR1__ */
 
+__BIONIC_FORTIFY_INLINE
+ssize_t recv(int socket, void* const buf __pass_object_size0, size_t len, int flags)
+    __overloadable
+    __clang_error_if(__bos0(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE && __bos0(buf) < len,
+                     "'recv' called with size bigger than buffer") {
+  return recvfrom(socket, buf, len, flags, NULL, 0);
+}
+
+__BIONIC_FORTIFY_INLINE
+ssize_t send(int socket, const void* const buf __pass_object_size0, size_t len, int flags)
+    __overloadable
+    __clang_error_if(__bos0(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE && __bos0(buf) < len,
+                     "'send' called with size bigger than buffer") {
+  return sendto(socket, buf, len, flags, NULL, 0);
+}
+
 #else /* defined(__clang__) */
 ssize_t __recvfrom_real(int, void*, size_t, int, struct sockaddr*, socklen_t*) __RENAME(recvfrom);
 __errordecl(__recvfrom_error, __recvfrom_bad_size);
@@ -147,20 +138,17 @@
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_N_MR1__ */
 
-#endif /* defined(__clang__) */
-#undef __recvfrom_bad_size
-#undef __sendto_bad_size
-
 __BIONIC_FORTIFY_INLINE
-ssize_t recv(int socket, void* const buf __pass_object_size0, size_t len,
-             int flags) __overloadable {
+ssize_t recv(int socket, void* buf, size_t len, int flags) {
   return recvfrom(socket, buf, len, flags, NULL, 0);
 }
 
 __BIONIC_FORTIFY_INLINE
-ssize_t send(int socket, const void* const buf __pass_object_size0, size_t len, int flags)
-        __overloadable {
+ssize_t send(int socket, const void* buf, size_t len, int flags) {
   return sendto(socket, buf, len, flags, NULL, 0);
 }
+#endif /* defined(__clang__) */
 
+#undef __recvfrom_bad_size
+#undef __sendto_bad_size
 #endif /* __BIONIC_FORTIFY */
diff --git a/libc/include/bits/fortify/stat.h b/libc/include/bits/fortify/stat.h
index d119e2c..c168c38 100644
--- a/libc/include/bits/fortify/stat.h
+++ b/libc/include/bits/fortify/stat.h
@@ -33,23 +33,17 @@
 mode_t __umask_chk(mode_t) __INTRODUCED_IN(18);
 
 #if defined(__BIONIC_FORTIFY)
-#define __umask_invalid_mode_str "umask called with invalid mode"
+#define __umask_invalid_mode_str "'umask' called with invalid mode"
 
 #if defined(__clang__)
 
 #if __ANDROID_API__ >= __ANDROID_API_J_MR2__
-/*
- * Abuse enable_if to make these be seen as overloads of umask, rather than
- * definitions.
- */
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-mode_t umask(mode_t mode) __overloadable
-        __enable_if(1, "")
-        __enable_if(mode & ~0777, __umask_invalid_mode_str)
-        __errorattr(__umask_invalid_mode_str);
-
+/* Abuse enable_if to make this an overload of umask. */
 __BIONIC_FORTIFY_INLINE
-mode_t umask(mode_t mode) __enable_if(1, "") __overloadable {
+mode_t umask(mode_t mode)
+    __overloadable
+    __enable_if(1, "")
+    __clang_error_if(mode & ~0777, __umask_invalid_mode_str) {
   return __umask_chk(mode);
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_J_MR2__ */
diff --git a/libc/include/bits/fortify/stdio.h b/libc/include/bits/fortify/stdio.h
index 4acefd7..cfc78d7 100644
--- a/libc/include/bits/fortify/stdio.h
+++ b/libc/include/bits/fortify/stdio.h
@@ -38,13 +38,13 @@
 
 #if __ANDROID_API__ >= __ANDROID_API_J_MR1__
 __BIONIC_FORTIFY_INLINE __printflike(3, 0)
-int vsnprintf(char *const __pass_object_size dest, size_t size,
-              const char * format, va_list ap) __overloadable {
+int vsnprintf(char* const __pass_object_size dest, size_t size, const char* format, va_list ap)
+        __overloadable {
     return __builtin___vsnprintf_chk(dest, size, 0, __bos(dest), format, ap);
 }
 
 __BIONIC_FORTIFY_INLINE __printflike(2, 0)
-int vsprintf(char *const __pass_object_size dest, const char* format, va_list ap) __overloadable {
+int vsprintf(char* const __pass_object_size dest, const char* format, va_list ap) __overloadable {
     return __builtin___vsprintf_chk(dest, 0, __bos(dest), format, ap);
 }
 #endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
@@ -59,14 +59,14 @@
 int snprintf(char* dest, size_t size, const char* format)
     __overloadable
     __enable_if(__bos(dest) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
-                __bos(dest) < __builtin_strlen(format),
+                    __bos(dest) < __builtin_strlen(format),
                 "format string will always overflow destination buffer")
     __errorattr("format string will always overflow destination buffer");
 
 __BIONIC_FORTIFY_INLINE
 __printflike(3, 4)
-int snprintf(char* const __pass_object_size dest,
-             size_t size, const char* format, ...) __overloadable {
+int snprintf(char* const __pass_object_size dest, size_t size, const char* format, ...)
+        __overloadable {
     va_list va;
     va_start(va, format);
     int result = __builtin___vsnprintf_chk(dest, size, 0, __bos(dest), format, va);
@@ -75,7 +75,8 @@
 }
 
 __BIONIC_ERROR_FUNCTION_VISIBILITY
-int sprintf(char* dest, const char* format) __overloadable
+int sprintf(char* dest, const char* format)
+    __overloadable
     __enable_if(__bos(dest) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
                 __bos(dest) < __builtin_strlen(format),
                 "format string will always overflow destination buffer")
@@ -94,44 +95,27 @@
 
 #if __ANDROID_API__ >= __ANDROID_API_N__
 __BIONIC_FORTIFY_INLINE
-size_t fread(void* buf, size_t size, size_t count,
-             FILE* stream) __overloadable
-        __enable_if(__unsafe_check_mul_overflow(size, count), "size * count overflows")
-        __errorattr("size * count overflows");
-
-__BIONIC_FORTIFY_INLINE
-size_t fread(void* buf, size_t size, size_t count, FILE* stream) __overloadable
-    __enable_if(!__unsafe_check_mul_overflow(size, count), "no overflow")
-    __enable_if(__bos(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
-                size * count > __bos(buf), "size * count is too large")
-    __errorattr("size * count is too large");
-
-__BIONIC_FORTIFY_INLINE
-size_t fread(void* const __pass_object_size0 buf, size_t size,
-             size_t count, FILE* stream) __overloadable {
+size_t fread(void* const __pass_object_size0 buf, size_t size, size_t count, FILE* stream)
+        __overloadable
+        __clang_error_if(__unsafe_check_mul_overflow(size, count),
+                         "in call to 'fread', size * count overflows")
+        __clang_error_if(__bos(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE && size * count > __bos(buf),
+                         "in call to 'fread', size * count is too large for the given buffer") {
     size_t bos = __bos0(buf);
 
     if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
         return __call_bypassing_fortify(fread)(buf, size, count, stream);
     }
-
     return __fread_chk(buf, size, count, stream, bos);
 }
 
-size_t fwrite(const void* buf, size_t size, size_t count, FILE* stream) __overloadable
-    __enable_if(__unsafe_check_mul_overflow(size, count),
-                "size * count overflows")
-    __errorattr("size * count overflows");
-
-size_t fwrite(const void* buf, size_t size, size_t count, FILE* stream) __overloadable
-    __enable_if(!__unsafe_check_mul_overflow(size, count), "no overflow")
-    __enable_if(__bos(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
-                size * count > __bos(buf), "size * count is too large")
-    __errorattr("size * count is too large");
-
 __BIONIC_FORTIFY_INLINE
 size_t fwrite(const void* const __pass_object_size0 buf, size_t size, size_t count, FILE* stream)
-        __overloadable {
+        __overloadable
+        __clang_error_if(__unsafe_check_mul_overflow(size, count),
+                         "in call to 'fwrite', size * count overflows")
+        __clang_error_if(__bos(buf) != __BIONIC_FORTIFY_UNKNOWN_SIZE && size * count > __bos(buf),
+                         "in call to 'fwrite', size * count is too large for the given buffer") {
     size_t bos = __bos0(buf);
 
     if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
@@ -143,19 +127,12 @@
 #endif /* __ANDROID_API__ >= __ANDROID_API_N__ */
 
 #if __ANDROID_API__ >= __ANDROID_API_J_MR1__
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-char *fgets(char* dest, int size, FILE* stream) __overloadable
-    __enable_if(size < 0, "size is negative")
-    __errorattr("size is negative");
-
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-char *fgets(char* dest, int size, FILE* stream) __overloadable
-    __enable_if(size >= 0 && size > __bos(dest),
-                "size is larger than the destination buffer")
-    __errorattr("size is larger than the destination buffer");
-
 __BIONIC_FORTIFY_INLINE
-char *fgets(char* const __pass_object_size dest, int size, FILE* stream) __overloadable {
+char* fgets(char* const __pass_object_size dest, int size, FILE* stream)
+        __overloadable
+        __clang_error_if(size < 0, "in call to 'fgets', size should not be negative")
+        __clang_error_if(size > __bos(dest),
+                         "in call to 'fgets', size is larger than the destination buffer") {
     size_t bos = __bos(dest);
 
     if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
diff --git a/libc/include/bits/fortify/stdlib.h b/libc/include/bits/fortify/stdlib.h
index bda1d45..cf4b7ea 100644
--- a/libc/include/bits/fortify/stdlib.h
+++ b/libc/include/bits/fortify/stdlib.h
@@ -32,22 +32,16 @@
 
 #if defined(__BIONIC_FORTIFY)
 #define __realpath_buf_too_small_str \
-    "realpath output parameter must be NULL or a >= PATH_MAX bytes buffer"
+    "'realpath' output parameter must be NULL or a pointer to a buffer with >= PATH_MAX bytes"
 
 /* PATH_MAX is unavailable without polluting the namespace, but it's always 4096 on Linux */
 #define __PATH_MAX 4096
 
 #if defined(__clang__)
-
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-char* realpath(const char* path, char* resolved) __overloadable
-    __enable_if(__bos(resolved) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
-                __bos(resolved) < __PATH_MAX, __realpath_buf_too_small_str)
-    __errorattr(__realpath_buf_too_small_str);
-
-/* No need for a FORTIFY version; the only things we can catch are at
- * compile-time.
- */
+char* realpath(const char* path, char* resolved)
+        __clang_error_if(__bos(resolved) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+                         __bos(resolved) < __PATH_MAX, __realpath_buf_too_small_str);
+/* No need for a definition; the only issues we can catch are at compile-time. */
 
 #else /* defined(__clang__) */
 
diff --git a/libc/include/sched.h b/libc/include/sched.h
index d407202..b8ef44b 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -25,6 +25,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _SCHED_H_
 #define _SCHED_H_
 
@@ -41,22 +42,22 @@
   int sched_priority;
 };
 
-int sched_setscheduler(pid_t, int, const struct sched_param*);
-int sched_getscheduler(pid_t);
+int sched_setscheduler(pid_t pid, int policy, const struct sched_param* param);
+int sched_getscheduler(pid_t pid);
 int sched_yield(void);
-int sched_get_priority_max(int);
-int sched_get_priority_min(int);
-int sched_setparam(pid_t, const struct sched_param*);
-int sched_getparam(pid_t, struct sched_param*);
-int sched_rr_get_interval(pid_t, struct timespec*);
+int sched_get_priority_max(int policy);
+int sched_get_priority_min(int policy);
+int sched_setparam(pid_t pid, const struct sched_param* param);
+int sched_getparam(pid_t pid, struct sched_param* param);
+int sched_rr_get_interval(pid_t pid, struct timespec* quantum);
 
 #if defined(__USE_GNU)
 
-int clone(int (*)(void*), void*, int, void*, ...) __INTRODUCED_IN_ARM(9)
-    __INTRODUCED_IN_MIPS(12) __INTRODUCED_IN_X86(17);
-int unshare(int) __INTRODUCED_IN(17);
+int clone(int (*fn)(void*), void* child_stack, int flags, void* arg, ...)
+    __INTRODUCED_IN_ARM(9) __INTRODUCED_IN_MIPS(12) __INTRODUCED_IN_X86(17);
+int unshare(int flags) __INTRODUCED_IN(17);
 int sched_getcpu(void) __INTRODUCED_IN(12);
-int setns(int, int) __INTRODUCED_IN(21);
+int setns(int fd, int ns_type) __INTRODUCED_IN(21);
 
 #ifdef __LP64__
 #define CPU_SETSIZE 1024
diff --git a/libc/include/stdio_ext.h b/libc/include/stdio_ext.h
index fdf6772..3c5abc3 100644
--- a/libc/include/stdio_ext.h
+++ b/libc/include/stdio_ext.h
@@ -40,7 +40,9 @@
 
 size_t __fbufsize(FILE*) __INTRODUCED_IN(23);
 int __freadable(FILE*) __INTRODUCED_IN(23);
+int __freading(FILE*) __INTRODUCED_IN_FUTURE;
 int __fwritable(FILE*) __INTRODUCED_IN(23);
+int __fwriting(FILE*) __INTRODUCED_IN_FUTURE;
 int __flbf(FILE*) __INTRODUCED_IN(23);
 void __fpurge(FILE*) __INTRODUCED_IN(23);
 size_t __fpending(FILE*) __INTRODUCED_IN(23);
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index 55e0fa2..13c9d37 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -83,8 +83,7 @@
 long atol(const char*) __attribute_pure__;
 long long atoll(const char*) __attribute_pure__;
 
-char * realpath(const char *path, char *resolved) __overloadable
-        __RENAME_CLANG(realpath);
+char* realpath(const char* path, char* resolved);
 int system(const char *string);
 
 void* bsearch(const void* key, const void* base0, size_t nmemb, size_t size,
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index d79e36b..06856c8 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1320,6 +1320,8 @@
 
 LIBC_P {
   global:
+    __freading; # future
+    __fwriting; # future
     getlogin_r; # future
 } LIBC_O;
 
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index ed1e82c..50e4390 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1240,6 +1240,8 @@
 
 LIBC_P {
   global:
+    __freading; # future
+    __fwriting; # future
     getlogin_r; # future
 } LIBC_O;
 
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index af8e550..3e4d36e 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1345,6 +1345,8 @@
 
 LIBC_P {
   global:
+    __freading; # future
+    __fwriting; # future
     getlogin_r; # future
 } LIBC_O;
 
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 90a65e0..3fa7c9d 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1304,6 +1304,8 @@
 
 LIBC_P {
   global:
+    __freading; # future
+    __fwriting; # future
     getlogin_r; # future
 } LIBC_O;
 
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index ed1e82c..50e4390 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1240,6 +1240,8 @@
 
 LIBC_P {
   global:
+    __freading; # future
+    __fwriting; # future
     getlogin_r; # future
 } LIBC_O;
 
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 8217562..bd74fbe 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1302,6 +1302,8 @@
 
 LIBC_P {
   global:
+    __freading; # future
+    __fwriting; # future
     getlogin_r; # future
 } LIBC_O;
 
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index ed1e82c..50e4390 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1240,6 +1240,8 @@
 
 LIBC_P {
   global:
+    __freading; # future
+    __fwriting; # future
     getlogin_r; # future
 } LIBC_O;
 
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index 6fb2c0d..bf6a8f8 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -127,10 +127,11 @@
 // Values for `__sFILE::_flags`.
 #define __SLBF 0x0001  // Line buffered.
 #define __SNBF 0x0002  // Unbuffered.
-// RD and WR are never simultaneously asserted: use _SRW instead.
-#define __SRD  0x0004  // OK to read.
-#define __SWR  0x0008  // OK to write.
-#define __SRW  0x0010  // Open for reading & writing.
+// __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 __SEOF 0x0020  // Found EOF.
 #define __SERR 0x0040  // Found error.
 #define __SMBF 0x0080  // `_buf` is from malloc.
diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
index ebc705c..8cf4f4b 100644
--- a/libc/stdio/stdio_ext.cpp
+++ b/libc/stdio/stdio_ext.cpp
@@ -39,17 +39,13 @@
   return fp->_bf._size;
 }
 
-/* For a _SRW stream, we don't know whether we last read or wrote.
 int __freading(FILE* fp) {
-  return (fp->_flags & _SRD) != 0 || ...;
+  return (fp->_flags & __SRD) != 0;
 }
-*/
 
-/* For a _SRW stream, we don't know whether we last read or wrote.
-int __fwriting(FILE*) {
-  return (fp->_flags & _SWR) != 0 || ...;
+int __fwriting(FILE* fp) {
+  return (fp->_flags & __SWR) != 0;
 }
-*/
 
 int __freadable(FILE* fp) {
   return (fp->_flags & (__SRD|__SRW)) != 0;
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/realpath.c b/libc/upstream-freebsd/lib/libc/stdlib/realpath.c
index 914ecc9..c4bd953 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/realpath.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/realpath.c
@@ -48,7 +48,7 @@
  * in which case the path which caused trouble is left in (resolved).
  */
 char *
-realpath(const char * __restrict path, char * __restrict resolved) __overloadable
+realpath(const char * __restrict path, char * __restrict resolved)
 {
 	struct stat sb;
 	char *p, *q, *s;
diff --git a/linker/Android.bp b/linker/Android.bp
index efd91ac..fda7eb5 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -101,6 +101,12 @@
         "-Werror",
     ],
 
+    product_variables: {
+        debuggable: {
+            cppflags: ["-DUSE_LD_CONFIG_FILE"],
+        },
+    },
+
     cppflags: ["-Wold-style-cast"],
 
     // we are going to link libc++_static manually because
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 8e7a141..a212624 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -558,9 +558,10 @@
 
   static LoadTask* create(const char* name,
                           soinfo* needed_by,
+                          android_namespace_t* start_from,
                           std::unordered_map<const soinfo*, ElfReader>* readers_map) {
     LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
-    return new (ptr) LoadTask(name, needed_by, readers_map);
+    return new (ptr) LoadTask(name, needed_by, start_from, readers_map);
   }
 
   const char* get_name() const {
@@ -612,6 +613,11 @@
     is_dt_needed_ = is_dt_needed;
   }
 
+  // returns the namespace from where we need to start loading this.
+  const android_namespace_t* get_start_from() const {
+    return start_from_;
+  }
+
   const ElfReader& get_elf_reader() const {
     CHECK(si_ != nullptr);
     return (*elf_readers_map_)[si_];
@@ -650,10 +656,11 @@
  private:
   LoadTask(const char* name,
            soinfo* needed_by,
+           android_namespace_t* start_from,
            std::unordered_map<const soinfo*, ElfReader>* readers_map)
     : name_(name), needed_by_(needed_by), si_(nullptr),
       fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
-      is_dt_needed_(false) {}
+      is_dt_needed_(false), start_from_(start_from) {}
 
   ~LoadTask() {
     if (fd_ != -1 && close_fd_) {
@@ -672,6 +679,7 @@
   // TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
   bool is_dt_needed_;
   // END OF WORKAROUND
+  const android_namespace_t* const start_from_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
 };
@@ -1041,7 +1049,7 @@
                         ZipArchiveCache* zip_archive_cache,
                         const char* name, soinfo *needed_by,
                         off64_t* file_offset, std::string* realpath) {
-  TRACE("[ opening %s ]", name);
+  TRACE("[ opening %s at namespace %s]", name, ns->get_name());
 
   // If the name contains a slash, we should attempt to open it directly and not search the paths.
   if (strchr(name, '/') != nullptr) {
@@ -1273,7 +1281,7 @@
   }
 
   for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
-    load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
+    load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map()));
   });
 
   return true;
@@ -1368,8 +1376,7 @@
 }
 
 static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
-                                             LoadTask* task,
-                                             int rtld_flags) {
+                                             LoadTask* task) {
   android_namespace_t* ns = namespace_link.linked_namespace();
 
   soinfo* candidate;
@@ -1394,29 +1401,10 @@
     return true;
   }
 
-  // try to load the library - once namespace boundary is crossed
-  // we need to load a library within separate load_group
-  // to avoid using symbols from foreign namespace while.
-  //
-  // All symbols during relocation should be resolved within a
-  // namespace to preserve library locality to a namespace.
-  const char* name = task->get_name();
-  if (find_libraries(ns,
-                     task->get_needed_by(),
-                     &name,
-                     1,
-                     &candidate,
-                     nullptr /* ld_preloads */,
-                     0 /* ld_preload_count*/,
-                     rtld_flags,
-                     nullptr /* extinfo*/,
-                     false /* add_as_children */,
-                     false /* search_linked_namespaces */)) {
-    task->set_soinfo(candidate);
-    return true;
-  }
-
-  return false;
+  // returning true with empty soinfo means that the library is okay to be
+  // loaded in the namespace buy has not yet been loaded there before.
+  task->set_soinfo(nullptr);
+  return true;
 }
 
 static bool find_library_internal(android_namespace_t* ns,
@@ -1445,9 +1433,24 @@
     // if a library was not found - look into linked namespaces
     for (auto& linked_namespace : ns->linked_namespaces()) {
       if (find_library_in_linked_namespace(linked_namespace,
-                                           task,
-                                           rtld_flags)) {
-        return true;
+                                           task)) {
+        if (task->get_soinfo() == nullptr) {
+          // try to load the library - once namespace boundary is crossed
+          // we need to load a library within separate load_group
+          // to avoid using symbols from foreign namespace while.
+          //
+          // However, actual linking is deferred until when the global group
+          // is fully identified and is applied to all namespaces.
+          // Otherwise, the libs in the linked namespace won't get symbols from
+          // the global group.
+          if (load_library(linked_namespace.linked_namespace(), task, zip_archive_cache, load_tasks, rtld_flags, false)) {
+            return true;
+          }
+          // lib was not found in the namespace. Try next linked namespace.
+        } else {
+          // lib is already loaded
+          return true;
+        }
       }
     }
   }
@@ -1458,44 +1461,6 @@
 static void soinfo_unload(soinfo* si);
 static void soinfo_unload(soinfo* soinfos[], size_t count);
 
-// TODO: this is slightly unusual way to construct
-// the global group for relocation. Not every RTLD_GLOBAL
-// library is included in this group for backwards-compatibility
-// reasons.
-//
-// This group consists of the main executable, LD_PRELOADs
-// and libraries with the DF_1_GLOBAL flag set.
-static soinfo_list_t make_global_group(android_namespace_t* ns) {
-  soinfo_list_t global_group;
-  ns->soinfo_list().for_each([&](soinfo* si) {
-    if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
-      global_group.push_back(si);
-    }
-  });
-
-  return global_group;
-}
-
-// This function provides a list of libraries to be shared
-// by the namespace. For the default namespace this is the global
-// group (see make_global_group). For all others this is a group
-// of RTLD_GLOBAL libraries (which includes the global group from
-// the default namespace).
-static soinfo_list_t get_shared_group(android_namespace_t* ns) {
-  if (ns == &g_default_namespace) {
-    return make_global_group(ns);
-  }
-
-  soinfo_list_t shared_group;
-  ns->soinfo_list().for_each([&](soinfo* si) {
-    if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
-      shared_group.push_back(si);
-    }
-  });
-
-  return shared_group;
-}
-
 static void shuffle(std::vector<LoadTask*>* v) {
   for (size_t i = 0, size = v->size(); i < size; ++i) {
     size_t n = size - i;
@@ -1518,19 +1483,17 @@
                     int rtld_flags,
                     const android_dlextinfo* extinfo,
                     bool add_as_children,
-                    bool search_linked_namespaces) {
+                    bool search_linked_namespaces,
+                    std::unordered_map<const soinfo*, ElfReader>& readers_map,
+                    std::vector<android_namespace_t*>* namespaces) {
   // Step 0: prepare.
   LoadTaskList load_tasks;
-  std::unordered_map<const soinfo*, ElfReader> readers_map;
 
   for (size_t i = 0; i < library_names_count; ++i) {
     const char* name = library_names[i];
-    load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
+    load_tasks.push_back(LoadTask::create(name, start_with, ns, &readers_map));
   }
 
-  // Construct global_group.
-  soinfo_list_t global_group = make_global_group(ns);
-
   // If soinfos array is null allocate one on stack.
   // The array is needed in case of failure; for example
   // when library_names[] = {libone.so, libtwo.so} and libone.so
@@ -1570,7 +1533,12 @@
     task->set_extinfo(is_dt_needed ? nullptr : extinfo);
     task->set_dt_needed(is_dt_needed);
 
-    if (!find_library_internal(ns,
+    // try to find the load.
+    // Note: start from the namespace that is stored in the LoadTask. This namespace
+    // is different from the current namespace when the LoadTask is for a transitive
+    // dependency and the lib that created the LoadTask is not found in the
+    // current namespace but in one of the linked namespace.
+    if (!find_library_internal(const_cast<android_namespace_t*>(task->get_start_from()),
                                task,
                                &zip_archive_cache,
                                &load_tasks,
@@ -1629,18 +1597,61 @@
     }
   }
 
-  // Step 4: Add LD_PRELOADed libraries to the global group for
-  // future runs. There is no need to explicitly add them to
-  // the global group for this run because they are going to
-  // appear in the local group in the correct order.
+  // Step 4: Construct the global group. Note: DF_1_GLOBAL bit of a library is
+  // determined at step 3.
+
+  // Step 4-1: DF_1_GLOBAL bit is force set for LD_PRELOADed libs because they
+  // must be added to the global group
   if (ld_preloads != nullptr) {
     for (auto&& si : *ld_preloads) {
       si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
     }
   }
 
+  // Step 4-2: Gather all DF_1_GLOBAL libs which were newly loaded during this
+  // run. These will be the new member of the global group
+  soinfo_list_t new_global_group_members;
+  for (auto&& task : load_tasks) {
+    soinfo* si = task->get_soinfo();
+    if (!si->is_linked() && (si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
+      new_global_group_members.push_back(si);
+    }
+  }
 
-  // Step 5: link libraries.
+  // Step 4-3: Add the new global group members to all the linked namespaces
+  for (auto si : new_global_group_members) {
+    for (auto linked_ns : *namespaces) {
+      if (si->get_primary_namespace() != linked_ns) {
+        linked_ns->add_soinfo(si);
+        si->add_secondary_namespace(linked_ns);
+      }
+    }
+  }
+
+  // Step 5: link libraries that are not destined to this namespace.
+  // Do this by recursively calling find_libraries on the namespace where the lib
+  // was found during Step 1.
+  for (auto&& task : load_tasks) {
+    soinfo* si = task->get_soinfo();
+    if (si->get_primary_namespace() != ns) {
+      const char* name = task->get_name();
+      if (find_libraries(si->get_primary_namespace(), task->get_needed_by(), &name, 1,
+                         nullptr /* soinfos */, nullptr /* ld_preloads */, 0 /* ld_preload_count */,
+                         rtld_flags, nullptr /* extinfo */, false /* add_as_children */,
+                         false /* search_linked_namespaces */, readers_map, namespaces)) {
+        // If this lib is directly needed by one of the libs in this namespace,
+        // then increment the count
+        soinfo* needed_by = task->get_needed_by();
+        if (needed_by != nullptr && needed_by->get_primary_namespace() == ns && si->is_linked()) {
+          si->increment_ref_count();
+        }
+      } else {
+        return false;
+      }
+    }
+  }
+
+  // Step 6: link libraries in this namespace
   soinfo_list_t local_group;
   walk_dependencies_tree(
       (start_with != nullptr && add_as_children) ? &start_with : soinfos,
@@ -1654,6 +1665,7 @@
     }
   });
 
+  soinfo_list_t global_group = ns->get_global_group();
   bool linked = local_group.visit([&](soinfo* si) {
     if (!si->is_linked()) {
       if (!si->link_image(global_group, local_group, extinfo) ||
@@ -1684,6 +1696,9 @@
                             soinfo* needed_by) {
   soinfo* si;
 
+  // readers_map is shared across recursive calls to find_libraries.
+  // However, the map is not shared across different threads.
+  std::unordered_map<const soinfo*, ElfReader> readers_map;
   if (name == nullptr) {
     si = solist_get_somain();
   } else if (!find_libraries(ns,
@@ -1696,7 +1711,8 @@
                              rtld_flags,
                              extinfo,
                              false /* add_as_children */,
-                             true /* search_linked_namespaces */)) {
+                             true /* search_linked_namespaces */,
+                             readers_map)) {
     return nullptr;
   }
 
@@ -2208,7 +2224,7 @@
     }
   } else {
     // If not shared - copy only the shared group
-    add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
+    add_soinfos_to_namespace(parent_namespace->get_shared_group(), ns);
   }
 
   ns->set_ld_library_paths(std::move(ld_library_paths));
@@ -3413,7 +3429,7 @@
   return true;
 }
 
-static void init_default_namespace_no_config(bool is_asan) {
+static std::vector<android_namespace_t*> init_default_namespace_no_config(bool is_asan) {
   g_default_namespace.set_isolated(false);
   auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : kDefaultLdPaths;
 
@@ -3428,9 +3444,13 @@
   }
 
   g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
+
+  std::vector<android_namespace_t*> namespaces;
+  namespaces.push_back(&g_default_namespace);
+  return namespaces;
 }
 
-void init_default_namespace(const char* executable_path) {
+std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path) {
   g_default_namespace.set_name("(default)");
 
   soinfo* somain = solist_get_somain();
@@ -3447,14 +3467,24 @@
 
   std::string error_msg;
 
-  if (!Config::read_binary_config(kLdConfigFilePath,
+  const char* config_file = kLdConfigFilePath;
+#ifdef USE_LD_CONFIG_FILE
+  // This is a debugging/testing only feature. Must not be available on
+  // production builds.
+  const char* ld_config_file = getenv("LD_CONFIG_FILE");
+  if (ld_config_file != nullptr && file_exists(ld_config_file)) {
+    config_file = ld_config_file;
+  }
+#endif
+
+  if (!Config::read_binary_config(config_file,
                                   executable_path,
                                   g_is_asan,
                                   &config,
                                   &error_msg)) {
     if (!error_msg.empty()) {
       DL_WARN("error reading config file \"%s\" for \"%s\" (will use default configuration): %s",
-              kLdConfigFilePath,
+              config_file,
               executable_path,
               error_msg.c_str());
     }
@@ -3462,8 +3492,7 @@
   }
 
   if (config == nullptr) {
-    init_default_namespace_no_config(g_is_asan);
-    return;
+    return init_default_namespace_no_config(g_is_asan);
   }
 
   const auto& namespace_configs = config->namespace_configs();
@@ -3514,10 +3543,17 @@
   soinfo* ld_android_so = solist_get_head();
   for (auto it : namespaces) {
     it.second->add_soinfo(ld_android_so);
-    // TODO (dimitry): somain and ld_preloads should probably be added to all of these namespaces too?
+    // somain and ld_preloads are added to these namespaces after LD_PRELOAD libs are linked
   }
 
   set_application_target_sdk_version(config->target_sdk_version());
+
+  std::vector<android_namespace_t*> created_namespaces;
+  created_namespaces.reserve(namespaces.size());
+  for (auto kv : namespaces) {
+    created_namespaces.push_back(kv.second);
+  }
+  return created_namespaces;
 }
 
 // This function finds a namespace exported in ld.config.txt by its name.
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index bcb2281..54593e4 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -341,12 +341,19 @@
 
   somain = si;
 
-  init_default_namespace(executable_path);
+  std::vector<android_namespace_t*> namespaces = init_default_namespaces(executable_path);
 
   if (!si->prelink_image()) __linker_cannot_link(g_argv[0]);
 
   // add somain to global group
   si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
+  // ... and add it to all other linked namespaces
+  for (auto linked_ns : namespaces) {
+    if (linked_ns != &g_default_namespace) {
+      linked_ns->add_soinfo(somain);
+      somain->add_secondary_namespace(linked_ns);
+    }
+  }
 
   // Load ld_preloads and dependencies.
   std::vector<const char*> needed_library_name_list;
@@ -364,6 +371,9 @@
   const char** needed_library_names = &needed_library_name_list[0];
   size_t needed_libraries_count = needed_library_name_list.size();
 
+  // readers_map is shared across recursive calls to find_libraries so that we
+  // don't need to re-load elf headers.
+  std::unordered_map<const soinfo*, ElfReader> readers_map;
   if (needed_libraries_count > 0 &&
       !find_libraries(&g_default_namespace,
                       si,
@@ -375,7 +385,9 @@
                       RTLD_GLOBAL,
                       nullptr,
                       true /* add_as_children */,
-                      true /* search_linked_namespaces */)) {
+                      true /* search_linked_namespaces */,
+                      readers_map,
+                      &namespaces)) {
     __linker_cannot_link(g_argv[0]);
   } else if (needed_libraries_count == 0) {
     if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {
diff --git a/linker/linker_main.h b/linker/linker_main.h
index 8f3f07c..2cf30c2 100644
--- a/linker/linker_main.h
+++ b/linker/linker_main.h
@@ -31,6 +31,9 @@
 
 #include <android/dlext.h>
 
+#include <unordered_map>
+#include <vector>
+
 #include "linker_namespaces.h"
 #include "linker_soinfo.h"
 
@@ -44,7 +47,9 @@
   static size_t ref_count_;
 };
 
-void init_default_namespace(const char* executable_path);
+class ElfReader;
+
+std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path);
 soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
                      struct stat* file_stat, off64_t file_offset,
                      uint32_t rtld_flags);
@@ -59,7 +64,9 @@
                     int rtld_flags,
                     const android_dlextinfo* extinfo,
                     bool add_as_children,
-                    bool search_linked_namespaces);
+                    bool search_linked_namespaces,
+                    std::unordered_map<const soinfo*, ElfReader>& readers_map,
+                    std::vector<android_namespace_t*>* namespaces = nullptr);
 
 void solist_add_soinfo(soinfo* si);
 bool solist_remove_soinfo(soinfo* si);
diff --git a/linker/linker_namespaces.cpp b/linker/linker_namespaces.cpp
index 3c86f99..9fdf0b5 100644
--- a/linker/linker_namespaces.cpp
+++ b/linker/linker_namespaces.cpp
@@ -31,6 +31,8 @@
 #include "linker_soinfo.h"
 #include "linker_utils.h"
 
+#include <dlfcn.h>
+
 bool android_namespace_t::is_accessible(const std::string& file) {
   if (!is_isolated_) {
     return true;
@@ -86,3 +88,41 @@
     return !is_accessible_ftor(si);
   });
 }
+
+// TODO: this is slightly unusual way to construct
+// the global group for relocation. Not every RTLD_GLOBAL
+// library is included in this group for backwards-compatibility
+// reasons.
+//
+// This group consists of the main executable, LD_PRELOADs
+// and libraries with the DF_1_GLOBAL flag set.
+soinfo_list_t android_namespace_t::get_global_group() {
+  soinfo_list_t global_group;
+  soinfo_list().for_each([&](soinfo* si) {
+    if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
+      global_group.push_back(si);
+    }
+  });
+
+  return global_group;
+}
+
+// This function provides a list of libraries to be shared
+// by the namespace. For the default namespace this is the global
+// group (see get_global_group). For all others this is a group
+// of RTLD_GLOBAL libraries (which includes the global group from
+// the default namespace).
+soinfo_list_t android_namespace_t::get_shared_group() {
+  if (this == &g_default_namespace) {
+    return get_global_group();
+  }
+
+  soinfo_list_t shared_group;
+  soinfo_list().for_each([&](soinfo* si) {
+    if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
+      shared_group.push_back(si);
+    }
+  });
+
+  return shared_group;
+}
diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h
index 1099b6b..16906d6 100644
--- a/linker/linker_namespaces.h
+++ b/linker/linker_namespaces.h
@@ -136,6 +136,9 @@
   // or one of it's parent soinfos belongs to this namespace.
   bool is_accessible(soinfo* si);
 
+  soinfo_list_t get_global_group();
+  soinfo_list_t get_shared_group();
+
  private:
   const char* name_;
   bool is_isolated_;
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 42c29c8..a9873c4 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -147,8 +147,9 @@
 }
 
 bool ElfReader::Read(const char* name, int fd, off64_t file_offset, off64_t file_size) {
-  CHECK(!did_read_);
-  CHECK(!did_load_);
+  if (did_read_) {
+    return true;
+  }
   name_ = name;
   fd_ = fd;
   file_offset_ = file_offset;
@@ -167,7 +168,9 @@
 
 bool ElfReader::Load(const android_dlextinfo* extinfo) {
   CHECK(did_read_);
-  CHECK(!did_load_);
+  if (did_load_) {
+    return true;
+  }
   if (ReserveAddressSpace(extinfo) &&
       LoadSegments() &&
       FindPhdr()) {
diff --git a/tests/Android.bp b/tests/Android.bp
index 8f1c11f..084d393 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -298,7 +298,13 @@
                 "libLLVMSupport",
             ],
         }
-    }
+    },
+
+    product_variables: {
+        debuggable: {
+            cppflags: ["-DUSE_LD_CONFIG_FILE"],
+        },
+    },
 }
 
 // -----------------------------------------------------------------------------
@@ -592,6 +598,12 @@
     sanitize: {
         never: false,
     },
+
+    product_variables: {
+        debuggable: {
+            cppflags: ["-DUSE_LD_CONFIG_FILE"],
+        },
+    },
 }
 
 subdirs = ["libs"]
diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp
index aa8bd57..857640a 100644
--- a/tests/dl_test.cpp
+++ b/tests/dl_test.cpp
@@ -23,6 +23,8 @@
 #include <stdint.h>
 
 #include <string>
+#include <iostream>
+#include <fstream>
 
 #include "gtest_globals.h"
 #include "utils.h"
@@ -109,4 +111,131 @@
 #endif
 }
 
-// TODO: Add tests for LD_PRELOADs
+
+TEST(dl, exec_without_ld_preload) {
+#if defined(__BIONIC__)
+  std::string helper = get_testlib_root() +
+      "/ld_preload_test_helper/ld_preload_test_helper";
+  chmod(helper.c_str(), 0755);
+  ExecTestHelper eth;
+  eth.SetArgs({ helper.c_str(), nullptr });
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "12345");
+#endif
+}
+
+TEST(dl, exec_with_ld_preload) {
+#if defined(__BIONIC__)
+  std::string helper = get_testlib_root() +
+      "/ld_preload_test_helper/ld_preload_test_helper";
+  std::string env = std::string("LD_PRELOAD=") + get_testlib_root() + "/ld_preload_test_helper_lib2.so";
+  chmod(helper.c_str(), 0755);
+  ExecTestHelper eth;
+  eth.SetArgs({ helper.c_str(), nullptr });
+  eth.SetEnv({ env.c_str(), nullptr });
+  // ld_preload_test_helper calls get_value_from_lib() and returns the value.
+  // The symbol is defined by two libs: ld_preload_test_helper_lib.so and
+  // ld_preloaded_lib.so. The former is DT_NEEDED and the latter is LD_PRELOADED
+  // via this execution. The main executable is linked to the LD_PRELOADED lib
+  // and the value given from the lib is returned.
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "54321");
+#endif
+}
+
+
+// ld_config_test_helper must fail because it is depending on a lib which is not
+// in the search path
+//
+// Call sequence is...
+// _helper -- (get_value_from_lib()) -->
+//     _lib1.so -- (get_value_from_another_lib()) -->
+//       _lib2.so (returns 12345)
+// The two libs are in ns2/ subdir.
+TEST(dl, exec_without_ld_config_file) {
+#if defined(__BIONIC__)
+  std::string error_message = "CANNOT LINK EXECUTABLE \"" + get_testlib_root() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
+  std::string helper = get_testlib_root() +
+      "/ld_config_test_helper/ld_config_test_helper";
+  chmod(helper.c_str(), 0755);
+  ExecTestHelper eth;
+  eth.SetArgs({ helper.c_str(), nullptr });
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, -6, error_message.c_str());
+#endif
+}
+
+#if defined(__BIONIC__)
+static void create_ld_config_file(std::string& config_file) {
+  std::ofstream fout(config_file.c_str(), std::ios::out);
+  fout << "dir.test = " << get_testlib_root() << "/ld_config_test_helper/" << std::endl
+       << "[test]" << std::endl
+       << "additional.namespaces = ns2" << std::endl
+       << "namespace.default.search.paths = " << get_testlib_root() << std::endl
+       << "namespace.default.links = ns2" << std::endl
+       << "namespace.default.link.ns2.shared_libs = libc.so:libm.so:libdl.so:ld_config_test_helper_lib1.so" << std::endl
+       << "namespace.ns2.search.paths = /system/${LIB}:" << get_testlib_root() << "/ns2" << std::endl;
+  fout.close();
+}
+#endif
+
+#ifdef USE_LD_CONFIG_FILE
+
+// _lib1.so and _lib2.so are now searchable by having another namespace 'ns2'
+// whose search paths include the 'ns2/' subdir.
+TEST(dl, exec_with_ld_config_file) {
+#if defined(__BIONIC__)
+  std::string helper = get_testlib_root() +
+      "/ld_config_test_helper/ld_config_test_helper";
+  std::string config_file = get_testlib_root() + "/ld.config.txt";
+  create_ld_config_file(config_file);
+  std::string env = std::string("LD_CONFIG_FILE=") + config_file;
+  chmod(helper.c_str(), 0755);
+  ExecTestHelper eth;
+  eth.SetArgs({ helper.c_str(), nullptr });
+  eth.SetEnv({ env.c_str(), nullptr });
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "12345");
+#endif
+}
+
+// _lib3.so has same symbol as lib2.so but returns 54321. _lib3.so is
+// LD_PRELOADed. This test is to ensure LD_PRELOADed libs are available to
+// additional namespaces other than the default namespace.
+TEST(dl, exec_with_ld_config_file_with_ld_preload) {
+#if defined(__BIONIC__)
+  std::string helper = get_testlib_root() +
+      "/ld_config_test_helper/ld_config_test_helper";
+  std::string config_file = get_testlib_root() + "/ld.config.txt";
+  create_ld_config_file(config_file);
+  std::string env = std::string("LD_CONFIG_FILE=") + config_file;
+  std::string env2 = std::string("LD_PRELOAD=") + get_testlib_root() + "/ld_config_test_helper_lib3.so";
+  chmod(helper.c_str(), 0755);
+  ExecTestHelper eth;
+  eth.SetArgs({ helper.c_str(), nullptr });
+  eth.SetEnv({ env.c_str(), env2.c_str(), nullptr });
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "54321");
+#endif
+}
+
+#endif // USE_LD_CONFIG_FILE
+
+// ensures that LD_CONFIG_FILE env var does not work for production builds.
+// The test input is the same as exec_with_ld_config_file, but it must fail in
+// this case.
+TEST(dl, disable_ld_config_file) {
+#if defined(__BIONIC__)
+  if (getuid() == 0) {
+    // when executed from the shell (e.g. not as part of CTS), skip the test.
+    // This test is only for CTS.
+    return;
+  }
+  std::string error_message = "CANNOT LINK EXECUTABLE \"" + get_testlib_root() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
+  std::string helper = get_testlib_root() +
+      "/ld_config_test_helper/ld_config_test_helper";
+  std::string config_file = get_testlib_root() + "/ld.config.txt";
+  create_ld_config_file(config_file);
+  std::string env = std::string("LD_CONFIG_FILE=") + config_file;
+  chmod(helper.c_str(), 0755);
+  ExecTestHelper eth;
+  eth.SetArgs({ helper.c_str(), nullptr });
+  eth.SetEnv({ env.c_str(), nullptr });
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, -6, error_message.c_str());
+#endif
+}
diff --git a/tests/fortify_compilation_test.cpp b/tests/fortify_compilation_test.cpp
index 7def77e..db800a2 100644
--- a/tests/fortify_compilation_test.cpp
+++ b/tests/fortify_compilation_test.cpp
@@ -179,12 +179,12 @@
 
   // NOLINTNEXTLINE(whitespace/line_length)
   // GCC: error: call to '__fgets_too_small_error' declared with attribute error: fgets called with size less than zero
-  // CLANG: error: call to unavailable function 'fgets': size is negative
+  // CLANG: error: in call to 'fgets', size should not be negative
   fgets(buf, -1, stdin);
 
   // NOLINTNEXTLINE(whitespace/line_length)
   // GCC: error: call to '__fgets_too_big_error' declared with attribute error: fgets called with size bigger than buffer
-  // CLANG: error: call to unavailable function 'fgets': size is larger than the destination buffer
+  // CLANG: error: in call to 'fgets', size is larger than the destination buffer
   fgets(buf, 6, stdin);
 }
 
@@ -193,15 +193,24 @@
   sockaddr_in addr;
 
   // NOLINTNEXTLINE(whitespace/line_length)
-  // GCC: error: call to '__recvfrom_error' declared with attribute error: recvfrom called with size bigger than buffer
-  // CLANG: error: call to unavailable function 'recvfrom': recvfrom called with size bigger than buffer
+  // GCC: error: call to '__recvfrom_error' declared with attribute error: 'recvfrom' called with size bigger than buffer
+  // CLANG: error: 'recvfrom' called with size bigger than buffer
   recvfrom(0, buf, 6, 0, reinterpret_cast<sockaddr*>(&addr), NULL);
 }
 
+void test_recv() {
+  char buf[4] = {0};
+
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__recvfrom_error' declared with attribute error: 'recvfrom' called with size bigger than buffer
+  // CLANG: error: 'recv' called with size bigger than buffer
+  recv(0, buf, 6, 0);
+}
+
 void test_umask() {
   // NOLINTNEXTLINE(whitespace/line_length)
-  // GCC: error: call to '__umask_invalid_mode' declared with attribute error: umask called with invalid mode
-  // CLANG: error: call to unavailable function 'umask': umask called with invalid mode
+  // GCC: error: call to '__umask_invalid_mode' declared with attribute error: 'umask' called with invalid mode
+  // CLANG: error: 'umask' called with invalid mode
   umask(01777);
 }
 
@@ -216,7 +225,7 @@
 void test_open() {
   // NOLINTNEXTLINE(whitespace/line_length)
   // GCC: error: call to '__creat_missing_mode' declared with attribute error: called with O_CREAT, but missing mode
-  // CLANG: error: call to unavailable function 'open': called with O_CREAT, but missing mode
+  // CLANG: error: 'open' called with O_CREAT, but missing mode
   open("/dev/null", O_CREAT);
 
   // NOLINTNEXTLINE(whitespace/line_length)
@@ -229,7 +238,7 @@
   pollfd fds[1];
   // NOLINTNEXTLINE(whitespace/line_length)
   // GCC: error: call to '__poll_too_small_error' declared with attribute error: poll: pollfd array smaller than fd count
-  // CLANG: error: call to unavailable function 'poll': too many fds specified
+  // CLANG: error: in call to 'poll', fd_count is larger than the given buffer
   poll(fds, 2, 0);
 }
 
@@ -238,7 +247,7 @@
   timespec timeout;
   // 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: call to unavailable function 'ppoll': too many fds specified
+  // CLANG: error: in call to 'ppoll', fd_count is larger than the given buffer
   ppoll(fds, 2, &timeout, NULL);
 }
 
@@ -246,7 +255,7 @@
   char buf[4];
   // NOLINTNEXTLINE(whitespace/line_length)
   // GCC: error: call to '__fread_overflow' declared with attribute error: fread called with overflowing size * count
-  // CLANG: error: call to unavailable function 'fread': size * count overflows
+  // CLANG: error: in call to 'fread', size * count overflows
   fread(buf, 2, (size_t)-1, stdin);
 }
 
@@ -254,7 +263,8 @@
   char buf[4];
   // NOLINTNEXTLINE(whitespace/line_length)
   // GCC: error: call to '__fread_too_big_error' declared with attribute error: fread called with size * count bigger than buffer
-  // CLANG: error: call to unavailable function 'fread': size * count is too large
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // CLANG: error: in call to 'fread', size * count is too large for the given buffer
   fread(buf, 1, 5, stdin);
 }
 
@@ -262,7 +272,7 @@
   char buf[4] = {0};
   // NOLINTNEXTLINE(whitespace/line_length)
   // GCC: error: call to '__fwrite_overflow' declared with attribute error: fwrite called with overflowing size * count
-  // CLANG: error: call to unavailable function 'fwrite': size * count overflows
+  // CLANG: error: in call to 'fwrite', size * count overflows
   fwrite(buf, 2, (size_t)-1, stdout);
 }
 
@@ -270,7 +280,8 @@
   char buf[4] = {0};
   // NOLINTNEXTLINE(whitespace/line_length)
   // GCC: error: call to '__fwrite_too_big_error' declared with attribute error: fwrite called with size * count bigger than buffer
-  // CLANG: error: call to unavailable function 'fwrite': size * count is too large
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // CLANG: error: in call to 'fwrite', size * count is too large for the given buffer
   fwrite(buf, 1, 5, stdout);
 }
 
@@ -326,8 +337,8 @@
   sockaddr_in addr;
 
   // NOLINTNEXTLINE(whitespace/line_length)
-  // GCC: error: call to '__sendto_error' declared with attribute error: sendto called with size bigger than buffer
-  // CLANG: error: call to unavailable function 'sendto': sendto called with size bigger than buffer
+  // GCC: error: call to '__sendto_error' declared with attribute error: 'sendto' called with size bigger than buffer
+  // CLANG: error: 'sendto' called with size bigger than buffer
   sendto(0, buf, 6, 0, reinterpret_cast<sockaddr*>(&addr), sizeof(sockaddr_in));
 }
 
@@ -335,7 +346,22 @@
   char buf[4] = {0};
 
   // NOLINTNEXTLINE(whitespace/line_length)
-  // GCC: error: call to '__sendto_error' declared with attribute error: sendto called with size bigger than buffer
-  // CLANG: error: call to unavailable function 'send': send called with size bigger than buffer
+  // GCC: error: call to '__sendto_error' declared with attribute error: 'sendto' called with size bigger than buffer
+  // CLANG: error: 'send' called with size bigger than buffer
   send(0, buf, 6, 0);
 }
+
+void test_realpath() {
+  char buf[4] = {0};
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // GCC: error: call to '__realpath_size_error' declared with attribute error: 'realpath' output parameter must be NULL or a pointer to a buffer with >= PATH_MAX bytes
+  // NOLINTNEXTLINE(whitespace/line_length)
+  // CLANG: error: 'realpath' output parameter must be NULL or a pointer to a buffer with >= PATH_MAX bytes
+  realpath(".", buf);
+
+  // This is fine.
+  realpath(".", NULL);
+
+  // FIXME: But we should warn on this.
+  realpath(NULL, buf);
+}
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 973a8d2..c1600cc 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -617,3 +617,59 @@
     defaults: ["bionic_testlib_defaults"],
     srcs: ["preinit_syscall_test_helper.cpp"],
 }
+
+cc_test {
+    name: "ld_preload_test_helper",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["ld_preload_test_helper.cpp"],
+    shared_libs: ["ld_preload_test_helper_lib1"],
+    ldflags: ["-Wl,--rpath,${ORIGIN}/.."],
+}
+
+cc_test_library {
+    name: "ld_preload_test_helper_lib1",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["ld_preload_test_helper_lib1.cpp"],
+}
+
+cc_test_library {
+    name: "ld_preload_test_helper_lib2",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["ld_preload_test_helper_lib2.cpp"],
+}
+
+cc_test {
+    name: "ld_config_test_helper",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["ld_config_test_helper.cpp"],
+    shared_libs: ["ld_config_test_helper_lib1"],
+    ldflags: ["-Wl,--rpath,${ORIGIN}/.."],
+}
+
+cc_test_library {
+    name: "ld_config_test_helper_lib1",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["ld_config_test_helper_lib1.cpp"],
+    shared_libs: ["ld_config_test_helper_lib2"],
+    relative_install_path: "/ns2",
+}
+
+cc_test_library {
+    name: "ld_config_test_helper_lib2",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["ld_config_test_helper_lib2.cpp"],
+    relative_install_path: "/ns2",
+}
+
+cc_test_library {
+    name: "ld_config_test_helper_lib3",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["ld_config_test_helper_lib3.cpp"],
+}
diff --git a/tests/libs/ld_config_test_helper.cpp b/tests/libs/ld_config_test_helper.cpp
new file mode 100644
index 0000000..592e8c0
--- /dev/null
+++ b/tests/libs/ld_config_test_helper.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern int get_value_from_lib();
+
+int main() {
+  printf("%d", get_value_from_lib());
+  return 0;
+}
diff --git a/tests/libs/ld_config_test_helper_lib1.cpp b/tests/libs/ld_config_test_helper_lib1.cpp
new file mode 100644
index 0000000..fc5401a
--- /dev/null
+++ b/tests/libs/ld_config_test_helper_lib1.cpp
@@ -0,0 +1,4 @@
+extern int get_value_from_another_lib();
+int get_value_from_lib() {
+  return get_value_from_another_lib();
+}
diff --git a/tests/libs/ld_config_test_helper_lib2.cpp b/tests/libs/ld_config_test_helper_lib2.cpp
new file mode 100644
index 0000000..a620a6c
--- /dev/null
+++ b/tests/libs/ld_config_test_helper_lib2.cpp
@@ -0,0 +1,3 @@
+int get_value_from_another_lib() {
+  return 12345;
+}
diff --git a/tests/libs/ld_config_test_helper_lib3.cpp b/tests/libs/ld_config_test_helper_lib3.cpp
new file mode 100644
index 0000000..93d1cd8
--- /dev/null
+++ b/tests/libs/ld_config_test_helper_lib3.cpp
@@ -0,0 +1,3 @@
+int get_value_from_another_lib() {
+  return 54321;
+}
diff --git a/tests/libs/ld_preload_test_helper.cpp b/tests/libs/ld_preload_test_helper.cpp
new file mode 100644
index 0000000..592e8c0
--- /dev/null
+++ b/tests/libs/ld_preload_test_helper.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern int get_value_from_lib();
+
+int main() {
+  printf("%d", get_value_from_lib());
+  return 0;
+}
diff --git a/tests/libs/ld_preload_test_helper_lib1.cpp b/tests/libs/ld_preload_test_helper_lib1.cpp
new file mode 100644
index 0000000..74e89db
--- /dev/null
+++ b/tests/libs/ld_preload_test_helper_lib1.cpp
@@ -0,0 +1,3 @@
+int get_value_from_lib() {
+  return 12345;
+}
diff --git a/tests/libs/ld_preload_test_helper_lib2.cpp b/tests/libs/ld_preload_test_helper_lib2.cpp
new file mode 100644
index 0000000..9239891
--- /dev/null
+++ b/tests/libs/ld_preload_test_helper_lib2.cpp
@@ -0,0 +1,3 @@
+int get_value_from_lib() {
+  return 54321;
+}
diff --git a/tests/sched_test.cpp b/tests/sched_test.cpp
index a4cffc0..e70528e 100644
--- a/tests/sched_test.cpp
+++ b/tests/sched_test.cpp
@@ -270,3 +270,34 @@
   CPU_FREE(set1);
   CPU_FREE(set2);
 }
+
+TEST(sched, sched_get_priority_min_sched_get_priority_max) {
+  EXPECT_LE(sched_get_priority_min(SCHED_BATCH), sched_get_priority_max(SCHED_BATCH));
+  EXPECT_LE(sched_get_priority_min(SCHED_FIFO), sched_get_priority_max(SCHED_FIFO));
+  EXPECT_LE(sched_get_priority_min(SCHED_IDLE), sched_get_priority_max(SCHED_IDLE));
+  EXPECT_LE(sched_get_priority_min(SCHED_OTHER), sched_get_priority_max(SCHED_OTHER));
+  EXPECT_LE(sched_get_priority_min(SCHED_RR), sched_get_priority_max(SCHED_RR));
+}
+
+TEST(sched, sched_getscheduler_sched_setscheduler) {
+  // POSIX: "If pid is zero, the scheduling policy shall be returned for the
+  // calling process".
+  ASSERT_EQ(sched_getscheduler(getpid()), sched_getscheduler(0));
+
+  const int original_policy = sched_getscheduler(getpid());
+  sched_param p = {};
+  p.sched_priority = sched_get_priority_min(original_policy);
+  errno = 0;
+  ASSERT_EQ(-1, sched_setscheduler(getpid(), INT_MAX, &p));
+  ASSERT_EQ(EINVAL, errno);
+
+  ASSERT_EQ(0, sched_getparam(getpid(), &p));
+  ASSERT_EQ(original_policy, sched_setscheduler(getpid(), SCHED_BATCH, &p));
+  // POSIX says this should return the previous policy (here SCHED_BATCH),
+  // but the Linux system call doesn't, and the glibc wrapper doesn't correct
+  // this (the "returns 0" behavior is even documented on the man page in
+  // the BUGS section). This was our historical behavior too, so in the
+  // absence of reasons to break compatibility with ourselves and glibc, we
+  // don't behave as POSIX specifies. http://b/26203902.
+  ASSERT_EQ(0, sched_setscheduler(getpid(), original_policy, &p));
+}
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
index 7872567..128e255 100644
--- a/tests/stdio_ext_test.cpp
+++ b/tests/stdio_ext_test.cpp
@@ -116,20 +116,78 @@
 }
 
 TEST(stdio_ext, __freadable__fwritable) {
-  FILE* fp = fopen("/dev/null", "r");
+  FILE* fp;
+
+  // Read-only.
+  fp = fopen("/dev/null", "r");
   ASSERT_TRUE(__freadable(fp));
   ASSERT_FALSE(__fwritable(fp));
   fclose(fp);
 
+  // Write-only.
   fp = fopen("/dev/null", "w");
   ASSERT_FALSE(__freadable(fp));
   ASSERT_TRUE(__fwritable(fp));
   fclose(fp);
 
-  fp = fopen("/dev/null", "w+");
-  ASSERT_TRUE(__freadable(fp));
+  // Append (aka write-only).
+  fp = fopen("/dev/null", "a");
+  ASSERT_FALSE(__freadable(fp));
   ASSERT_TRUE(__fwritable(fp));
   fclose(fp);
+
+  // The three read-write modes.
+  for (auto read_write_mode : {"r+", "w+", "a+"}) {
+    fp = fopen("/dev/null", read_write_mode);
+    ASSERT_TRUE(__freadable(fp));
+    ASSERT_TRUE(__fwritable(fp));
+    fclose(fp);
+  }
+}
+
+TEST(stdio_ext, __freading__fwriting) {
+  FILE* fp;
+
+  // Append (aka write-only). Never reading. Always writing.
+  fp = fopen("/dev/zero", "a");
+  ASSERT_FALSE(__freading(fp)); // Not reading initially.
+  ASSERT_TRUE(__fwriting(fp)); // Writing initially.
+  ASSERT_TRUE(fputc('x', fp) != EOF);
+  ASSERT_FALSE(__freading(fp)); // Not reading after write.
+  ASSERT_TRUE(__fwriting(fp)); // Still writing after write.
+  fclose(fp);
+
+  // Write-only. Never reading. Always writing.
+  fp = fopen("/dev/zero", "w");
+  ASSERT_FALSE(__freading(fp)); // Not reading initially.
+  ASSERT_TRUE(__fwriting(fp)); // Writing initially.
+  ASSERT_TRUE(fputc('x', fp) != EOF);
+  ASSERT_FALSE(__freading(fp)); // Not reading after write.
+  ASSERT_TRUE(__fwriting(fp)); // Still writing after write.
+  fclose(fp);
+
+  // Read-only. Always reading. Never writing.
+  fp = fopen("/dev/zero", "r");
+  ASSERT_TRUE(__freading(fp)); // Reading initially.
+  ASSERT_FALSE(__fwriting(fp)); // Not writing initially.
+  ASSERT_TRUE(fgetc(fp) == 0);
+  ASSERT_TRUE(__freading(fp)); // Still reading after read.
+  ASSERT_FALSE(__fwriting(fp)); // Still not writing after read.
+  fclose(fp);
+
+  // The three read-write modes.
+  for (auto read_write_mode : {"r+", "w+", "a+"}) {
+    fp = fopen("/dev/zero", read_write_mode);
+    ASSERT_FALSE(__freading(fp)); // Not reading initially.
+    ASSERT_FALSE(__fwriting(fp)); // Not writing initially.
+    ASSERT_TRUE(fgetc(fp) == 0);
+    ASSERT_TRUE(__freading(fp)); // Reading after read.
+    ASSERT_FALSE(__fwriting(fp)); // Not writing after read.
+    ASSERT_TRUE(fputc('x', fp) != EOF);
+    ASSERT_FALSE(__freading(fp)); // Not reading after write.
+    ASSERT_TRUE(__fwriting(fp)); // Writing after write.
+    fclose(fp);
+  }
 }
 
 TEST(stdio_ext, __fsetlocking) {