Merge "POSIX says <locale.h> makes NULL visible."
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index 92db5d9..cf50664 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -217,8 +217,7 @@
 }
 
 ssize_t __recvfrom_chk(int socket, void* buf, size_t len, size_t buf_size,
-                       int flags, const sockaddr* src_addr,
-                       socklen_t* addrlen) {
+                       int flags, sockaddr* src_addr, socklen_t* addrlen) {
   __check_buffer_access("recvfrom", "write into", len, buf_size);
   return recvfrom(socket, buf, len, flags, src_addr, addrlen);
 }
diff --git a/libc/bionic/netinet_in.cpp b/libc/bionic/netinet_in.cpp
index dfa5d8d..2a7090a 100644
--- a/libc/bionic/netinet_in.cpp
+++ b/libc/bionic/netinet_in.cpp
@@ -29,6 +29,7 @@
 #include <netinet/in.h>
 
 #include <errno.h>
+#include <netdb.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <string.h>
diff --git a/libc/bionic/pthread_barrier.cpp b/libc/bionic/pthread_barrier.cpp
index 1bcd12a..1618222 100644
--- a/libc/bionic/pthread_barrier.cpp
+++ b/libc/bionic/pthread_barrier.cpp
@@ -42,7 +42,7 @@
   return 0;
 }
 
-int pthread_barrierattr_getpshared(pthread_barrierattr_t* attr, int* pshared) {
+int pthread_barrierattr_getpshared(const pthread_barrierattr_t* attr, int* pshared) {
   *pshared = (*attr & 1) ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE;
   return 0;
 }
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index 7be0ab7..4a23fec 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -29,10 +29,10 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
-#include <linux/uio.h>  // For UIO_MAXIOV.
 #include <pthread.h>
 #include <stdio.h>  // For FOPEN_MAX.
 #include <sys/auxv.h>
+#include <sys/param.h>
 #include <sys/resource.h>
 #include <sys/sysinfo.h>
 #include <time.h>
@@ -48,18 +48,39 @@
 
 long sysconf(int name) {
   switch (name) {
-    case _SC_ARG_MAX:           return ARG_MAX;
+    //
+    // Things we actually have to calculate...
+    //
+    case _SC_ARG_MAX:
+      // Not a constant since Linux 2.6.23; see fs/exec.c for details.
+      // At least 32 pages, otherwise a quarter of the stack limit.
+      return MAX(__sysconf_rlimit(RLIMIT_STACK) / 4, _KERNEL_ARG_MAX);
+
+    case _SC_AVPHYS_PAGES:      return get_avphys_pages();
+    case _SC_CHILD_MAX:         return __sysconf_rlimit(RLIMIT_NPROC);
+    case _SC_CLK_TCK:           return static_cast<long>(getauxval(AT_CLKTCK));
+    case _SC_NPROCESSORS_CONF:  return get_nprocs_conf();
+    case _SC_NPROCESSORS_ONLN:  return get_nprocs();
+    case _SC_OPEN_MAX:          return __sysconf_rlimit(RLIMIT_NOFILE);
+
+    case _SC_PAGESIZE:
+    case _SC_PAGE_SIZE:
+      // _SC_PAGESIZE and _SC_PAGE_SIZE are distinct, but return the same value.
+      return static_cast<long>(getauxval(AT_PAGESZ));
+
+    case _SC_PHYS_PAGES:        return get_phys_pages();
+
+    //
+    // Constants...
+    //
     case _SC_BC_BASE_MAX:       return _POSIX2_BC_BASE_MAX;   // Minimum requirement.
     case _SC_BC_DIM_MAX:        return _POSIX2_BC_DIM_MAX;    // Minimum requirement.
     case _SC_BC_SCALE_MAX:      return _POSIX2_BC_SCALE_MAX;  // Minimum requirement.
     case _SC_BC_STRING_MAX:     return _POSIX2_BC_STRING_MAX; // Minimum requirement.
-    case _SC_CHILD_MAX:         return __sysconf_rlimit(RLIMIT_NPROC);
-    case _SC_CLK_TCK:           return static_cast<long>(getauxval(AT_CLKTCK));
     case _SC_COLL_WEIGHTS_MAX:  return _POSIX2_COLL_WEIGHTS_MAX;  // Minimum requirement.
     case _SC_EXPR_NEST_MAX:     return _POSIX2_EXPR_NEST_MAX;     // Minimum requirement.
     case _SC_LINE_MAX:          return _POSIX2_LINE_MAX;          // Minimum requirement.
     case _SC_NGROUPS_MAX:       return NGROUPS_MAX;
-    case _SC_OPEN_MAX:          return __sysconf_rlimit(RLIMIT_NOFILE);
     case _SC_PASS_MAX:          return PASS_MAX;
     case _SC_2_C_BIND:          return _POSIX2_C_BIND;
     case _SC_2_C_DEV:           return _POSIX2_C_DEV;
@@ -84,12 +105,7 @@
     case _SC_XOPEN_REALTIME_THREADS: return _XOPEN_REALTIME_THREADS;
     case _SC_XOPEN_LEGACY:      return _XOPEN_LEGACY;
     case _SC_ATEXIT_MAX:        return LONG_MAX;    // Unlimited.
-    case _SC_IOV_MAX:           return UIO_MAXIOV;
-
-    // _SC_PAGESIZE and _SC_PAGE_SIZE are distinct, but return the same value.
-    case _SC_PAGESIZE:
-    case _SC_PAGE_SIZE:
-      return static_cast<long>(getauxval(AT_PAGESZ));
+    case _SC_IOV_MAX:           return IOV_MAX;
 
     case _SC_XOPEN_UNIX:        return _XOPEN_UNIX;
     case _SC_AIO_LISTIO_MAX:    return _POSIX_AIO_LISTIO_MAX;     // Minimum requirement.
@@ -132,10 +148,6 @@
     case _SC_THREAD_PRIO_INHERIT: return _POSIX_THREAD_PRIO_INHERIT;
     case _SC_THREAD_PRIO_PROTECT: return _POSIX_THREAD_PRIO_PROTECT;
     case _SC_THREAD_SAFE_FUNCTIONS:  return _POSIX_THREAD_SAFE_FUNCTIONS;
-    case _SC_NPROCESSORS_CONF:  return get_nprocs_conf();
-    case _SC_NPROCESSORS_ONLN:  return get_nprocs();
-    case _SC_PHYS_PAGES:        return get_phys_pages();
-    case _SC_AVPHYS_PAGES:      return get_avphys_pages();
     case _SC_MONOTONIC_CLOCK:   return _POSIX_VERSION;
 
     case _SC_2_PBS:             return -1;     // Obsolescent in POSIX.1-2008.
diff --git a/libc/bionic/sysinfo.cpp b/libc/bionic/sysinfo.cpp
index 1cb5c79..304634a 100644
--- a/libc/bionic/sysinfo.cpp
+++ b/libc/bionic/sysinfo.cpp
@@ -76,29 +76,14 @@
   return cpu_count;
 }
 
-static int __get_meminfo_page_count(const char* pattern) {
-  FILE* fp = fopen("/proc/meminfo", "re");
-  if (fp == NULL) {
-    return -1;
-  }
-
-  int page_count = -1;
-  char buf[256];
-  while (fgets(buf, sizeof(buf), fp) != NULL) {
-    long total;
-    if (sscanf(buf, pattern, &total) == 1) {
-      page_count = static_cast<int>(total / (sysconf(_SC_PAGE_SIZE) / 1024));
-      break;
-    }
-  }
-  fclose(fp);
-  return page_count;
-}
-
 long get_phys_pages() {
-  return __get_meminfo_page_count("MemTotal: %ld kB");
+  struct sysinfo si;
+  sysinfo(&si);
+  return (si.totalram * si.mem_unit) / sysconf(_SC_PAGE_SIZE);
 }
 
 long get_avphys_pages() {
-  return __get_meminfo_page_count("MemFree: %ld kB");
+  struct sysinfo si;
+  sysinfo(&si);
+  return ((si.freeram + si.bufferram) * si.mem_unit) / sysconf(_SC_PAGE_SIZE);
 }
diff --git a/libc/include/bits/seek_constants.h b/libc/include/bits/seek_constants.h
new file mode 100644
index 0000000..34c5866
--- /dev/null
+++ b/libc/include/bits/seek_constants.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BITS_SEEK_CONSTANTS_H_
+#define _BITS_SEEK_CONSTANTS_H_
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#endif
diff --git a/libc/include/cpio.h b/libc/include/cpio.h
new file mode 100644
index 0000000..ceeeb87
--- /dev/null
+++ b/libc/include/cpio.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CPIO_H_
+#define _CPIO_H_
+
+#include <sys/cdefs.h>
+
+#define C_IRUSR 0000400
+#define C_IWUSR 0000200
+#define C_IXUSR 0000100
+#define C_IRGRP 0000040
+#define C_IWGRP 0000020
+#define C_IXGRP 0000010
+#define C_IROTH 0000004
+#define C_IWOTH 0000002
+#define C_IXOTH 0000001
+#define C_ISUID 0004000
+#define C_ISGID 0002000
+#define C_ISVTX 0001000
+#define C_ISDIR 0040000
+#define C_ISFIFO 0010000
+#define C_ISREG 0100000
+#define C_ISBLK 0060000
+#define C_ISCHR 0020000
+#define C_ISCTG 0110000
+#define C_ISLNK 0120000
+#define C_ISSOCK 0140000
+
+#define MAGIC "070707"
+
+#endif /* _CPIO_H_ */
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 872a727..c49dbd0 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -37,6 +37,7 @@
 #include <linux/uio.h>
 
 #include <bits/fcntl.h>
+#include <bits/seek_constants.h>
 
 #if defined(__USE_GNU) || defined(__USE_BSD)
 #include <bits/lockf.h>
diff --git a/libc/include/netdb.h b/libc/include/netdb.h
index 7fcb11f..95f0986 100644
--- a/libc/include/netdb.h
+++ b/libc/include/netdb.h
@@ -192,6 +192,8 @@
  */
 #define	SCOPE_DELIMITER	'%'
 
+#define IPPORT_RESERVED 1024
+
 __BEGIN_DECLS
 
 /* BIONIC-BEGIN */
diff --git a/libc/include/netinet/in.h b/libc/include/netinet/in.h
index b524b05..00b5cf9 100644
--- a/libc/include/netinet/in.h
+++ b/libc/include/netinet/in.h
@@ -40,8 +40,6 @@
 
 __BEGIN_DECLS
 
-#define IPPORT_RESERVED  1024
-
 #define INET_ADDRSTRLEN 16
 
 typedef uint16_t in_port_t;
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 1153695..47dc153 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -232,8 +232,8 @@
 
 int pthread_barrierattr_init(pthread_barrierattr_t* _Nonnull attr) __INTRODUCED_IN(24);
 int pthread_barrierattr_destroy(pthread_barrierattr_t* _Nonnull attr) __INTRODUCED_IN(24);
-int pthread_barrierattr_getpshared(pthread_barrierattr_t* _Nonnull attr, int* _Nonnull pshared)
-  __INTRODUCED_IN(24);
+int pthread_barrierattr_getpshared(const pthread_barrierattr_t* _Nonnull attr,
+                                   int* _Nonnull pshared) __INTRODUCED_IN(24);
 int pthread_barrierattr_setpshared(pthread_barrierattr_t* _Nonnull attr, int pshared)
   __INTRODUCED_IN(24);
 
diff --git a/libc/include/semaphore.h b/libc/include/semaphore.h
index 4ef13af..218f22a 100644
--- a/libc/include/semaphore.h
+++ b/libc/include/semaphore.h
@@ -42,7 +42,7 @@
 #endif
 } sem_t;
 
-#define SEM_FAILED NULL
+#define SEM_FAILED __BIONIC_CAST(reinterpret_cast, sem_t*, 0)
 
 int sem_destroy(sem_t*);
 int sem_getvalue(sem_t*, int*);
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 097be3a..38021ef 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -47,6 +47,8 @@
 #define __need_NULL
 #include <stddef.h>
 
+#include <bits/seek_constants.h>
+
 __BEGIN_DECLS
 
 #if defined(__clang__)
@@ -106,10 +108,6 @@
 #define	L_tmpnam	1024	/* XXX must be == PATH_MAX */
 #define	TMP_MAX		308915776
 
-#define SEEK_SET 0
-#define SEEK_CUR 1
-#define SEEK_END 2
-
 /*
  * Functions defined in ANSI C standard.
  */
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index 223c3b2..6a275e4 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -291,18 +291,18 @@
 ssize_t recv(int, void*, size_t, int);
 
 __socketcall ssize_t sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t);
-__socketcall ssize_t recvfrom(int, void*, size_t, int, const struct sockaddr*, socklen_t*);
+__socketcall ssize_t recvfrom(int, void*, size_t, int, struct sockaddr*, socklen_t*);
 
 __errordecl(__recvfrom_error, "recvfrom called with size bigger than buffer");
-ssize_t __recvfrom_chk(int, void*, size_t, size_t, int, const struct sockaddr*, socklen_t*)
+ssize_t __recvfrom_chk(int, void*, size_t, size_t, int, struct sockaddr*, socklen_t*)
   __INTRODUCED_IN(21);
-ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*) __RENAME(recvfrom);
+ssize_t __recvfrom_real(int, void*, size_t, int, struct sockaddr*, socklen_t*) __RENAME(recvfrom);
 
 #if defined(__BIONIC_FORTIFY)
 
 #if __ANDROID_API__ >= 24
 __BIONIC_FORTIFY_INLINE
-ssize_t recvfrom(int fd, void* buf, size_t len, int flags, const struct sockaddr* src_addr, socklen_t* addr_len) {
+ssize_t recvfrom(int fd, void* buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addr_len) {
   size_t bos = __bos0(buf);
 
 #if !defined(__clang__)
diff --git a/libc/include/tar.h b/libc/include/tar.h
new file mode 100644
index 0000000..a5d7a36
--- /dev/null
+++ b/libc/include/tar.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _TAR_H_
+#define _TAR_H_
+
+#include <sys/cdefs.h>
+
+#define TMAGIC "ustar"
+#define TMAGLEN 6
+#define TVERSION "00"
+#define TVERSLEN 2
+
+#define REGTYPE '0'
+#define AREGTYPE '\0'
+#define LNKTYPE '1'
+#define SYMTYPE '2'
+#define CHRTYPE '3'
+#define BLKTYPE '4'
+#define DIRTYPE '5'
+#define FIFOTYPE '6'
+#define CONTTYPE '7'
+
+#define TSUID 04000
+#define TSGID 02000
+#define TSVTX 01000
+#define TUREAD 00400
+#define TUWRITE 00200
+#define TUEXEC 00100
+#define TGREAD 00040
+#define TGWRITE 00020
+#define TGEXEC 00010
+#define TOREAD 00004
+#define TOWRITE 00002
+#define TOEXEC 00001
+
+#endif /* _TAR_H_ */
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 86949de..ac7d4c2 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -39,6 +39,7 @@
 #include <bits/ioctl.h>
 #include <bits/lockf.h>
 #include <bits/posix_limits.h>
+#include <bits/seek_constants.h>
 #include <bits/sysconf.h>
 
 __BEGIN_DECLS
@@ -52,10 +53,6 @@
 #define W_OK 2
 #define R_OK 4
 
-#define SEEK_SET 0
-#define SEEK_CUR 1
-#define SEEK_END 2
-
 #define _PC_FILESIZEBITS 0
 #define _PC_LINK_MAX 1
 #define _PC_MAX_CANON 2
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index 773d22f..340af13 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -53,9 +53,10 @@
     "x86": {},
     }
 
-# Replace tokens in the output according to this mapping
+# Replace tokens in the output according to this mapping.
 kernel_token_replacements = {
-    "asm": "__asm__",
+    # The kernel's ARG_MAX is actually the "minimum" maximum (see fs/exec.c).
+    "ARG_MAX": "_KERNEL_ARG_MAX",
     # The kernel usage of __unused for unused struct fields conflicts with the macro defined in <sys/cdefs.h>.
     "__unused": "__linux_unused",
     # The kernel's _NSIG/NSIG are one less than the userspace value, so we need to move them aside.
diff --git a/libc/kernel/uapi/linux/limits.h b/libc/kernel/uapi/linux/limits.h
index 406d175..4441592 100644
--- a/libc/kernel/uapi/linux/limits.h
+++ b/libc/kernel/uapi/linux/limits.h
@@ -21,7 +21,7 @@
 #define NR_OPEN 1024
 #define NGROUPS_MAX 65536
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
-#define ARG_MAX 131072
+#define _KERNEL_ARG_MAX 131072
 #define LINK_MAX 127
 #define MAX_CANON 255
 #define MAX_INPUT 255
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index c41f3a0..bced722 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -604,9 +604,16 @@
     }
 
     if (file_length != 0) {
+      int prot = PFLAGS_TO_PROT(phdr->p_flags);
+      // W + E PT_LOAD segments are not allowed.
+      if ((prot & (PROT_EXEC | PROT_WRITE)) == (PROT_EXEC | PROT_WRITE)) {
+        DL_ERR_AND_LOG("\"%s\": W + E load segments are not allowed", name_.c_str());
+        return false;
+      }
+
       void* seg_addr = mmap64(reinterpret_cast<void*>(seg_page_start),
                             file_length,
-                            PFLAGS_TO_PROT(phdr->p_flags),
+                            prot,
                             MAP_FIXED|MAP_PRIVATE,
                             fd_,
                             file_offset_ + file_page_start);
diff --git a/tests/Android.mk b/tests/Android.mk
index 0da3b88..b329831 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -16,6 +16,20 @@
 
 LOCAL_PATH := $(call my-dir)
 
+# Move prebuilt test elf-files to $(TARGET_OUT_NATIVE_TESTS)
+include $(CLEAR_VARS)
+LOCAL_MULTILIB := both
+LOCAL_MODULE := libtest_invalid-rw_load_segment.so
+LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/prebuilt-elf-files
+LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/prebuilt-elf-files
+LOCAL_MODULE_CLASS := SHARED_LIBRARY
+
+LOCAL_SRC_FILES_arm := prebuilt-elf-files/arm/$(LOCAL_MODULE)
+LOCAL_SRC_FILES_arm64 := prebuilt-elf-files/arm64/$(LOCAL_MODULE)
+LOCAL_SRC_FILES_x86 := prebuilt-elf-files/x86/$(LOCAL_MODULE)
+LOCAL_SRC_FILES_x86_64 := prebuilt-elf-files/x86_64/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
 ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
 build_host := true
 else
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 5bf5861..a1c5801 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1142,3 +1142,23 @@
 
   dlclose(handle);
 }
+
+// Bionic specific tests
+#if defined(__BIONIC__)
+
+#if defined(__LP64__)
+#define NATIVE_TESTS_PATH "/nativetest64"
+#else
+#define NATIVE_TESTS_PATH "/nativetest"
+#endif
+
+#define PREBUILT_ELF_PATH NATIVE_TESTS_PATH "/prebuilt-elf-files"
+
+TEST(dlfcn, dlopen_invalid_rw_load_segment) {
+  std::string libpath = std::string(getenv("ANDROID_DATA")) + PREBUILT_ELF_PATH + "/libtest_invalid-rw_load_segment.so";
+  void* handle = dlopen(libpath.c_str(), RTLD_NOW);
+  ASSERT_TRUE(handle == nullptr);
+  std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W + E load segments are not allowed";
+  ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
+}
+#endif
diff --git a/tests/prebuilt-elf-files/arm/libtest_invalid-rw_load_segment.so b/tests/prebuilt-elf-files/arm/libtest_invalid-rw_load_segment.so
new file mode 100755
index 0000000..00d91ff
--- /dev/null
+++ b/tests/prebuilt-elf-files/arm/libtest_invalid-rw_load_segment.so
Binary files differ
diff --git a/tests/prebuilt-elf-files/arm64/libtest_invalid-rw_load_segment.so b/tests/prebuilt-elf-files/arm64/libtest_invalid-rw_load_segment.so
new file mode 100755
index 0000000..f61d2ed
--- /dev/null
+++ b/tests/prebuilt-elf-files/arm64/libtest_invalid-rw_load_segment.so
Binary files differ
diff --git a/tests/prebuilt-elf-files/x86/libtest_invalid-rw_load_segment.so b/tests/prebuilt-elf-files/x86/libtest_invalid-rw_load_segment.so
new file mode 100755
index 0000000..7a343c9
--- /dev/null
+++ b/tests/prebuilt-elf-files/x86/libtest_invalid-rw_load_segment.so
Binary files differ
diff --git a/tests/prebuilt-elf-files/x86_64/libtest_invalid-rw_load_segment.so b/tests/prebuilt-elf-files/x86_64/libtest_invalid-rw_load_segment.so
new file mode 100755
index 0000000..b39d0ca
--- /dev/null
+++ b/tests/prebuilt-elf-files/x86_64/libtest_invalid-rw_load_segment.so
Binary files differ
diff --git a/tests/sys_sysinfo_test.cpp b/tests/sys_sysinfo_test.cpp
index b00e13f..d7d0f6e 100644
--- a/tests/sys_sysinfo_test.cpp
+++ b/tests/sys_sysinfo_test.cpp
@@ -17,17 +17,28 @@
 #include <gtest/gtest.h>
 
 #include <sys/sysinfo.h>
+#include <unistd.h>
 
 TEST(sys_sysinfo, smoke) {
-  int nprocessor = get_nprocs();
-  ASSERT_GT(nprocessor, 0);
+  int nprocs = get_nprocs();
+  ASSERT_GT(nprocs, 0);
+  ASSERT_EQ(sysconf(_SC_NPROCESSORS_ONLN), nprocs);
 
-  int nprocessor_conf = get_nprocs_conf();
-  ASSERT_GE(nprocessor_conf, nprocessor);
+  int nprocs_conf = get_nprocs_conf();
+  ASSERT_GE(nprocs_conf, nprocs);
+  ASSERT_EQ(sysconf(_SC_NPROCESSORS_CONF), nprocs_conf);
 
   long avail_phys_pages = get_avphys_pages();
   ASSERT_GT(avail_phys_pages, 0);
+  ASSERT_EQ(sysconf(_SC_AVPHYS_PAGES), avail_phys_pages);
 
   long phys_pages = get_phys_pages();
   ASSERT_GE(phys_pages, avail_phys_pages);
+  ASSERT_EQ(sysconf(_SC_PHYS_PAGES), phys_pages);
+}
+
+TEST(sys_sysinfo, sysinfo) {
+  struct sysinfo si;
+  memset(&si, 0, sizeof(si));
+  ASSERT_EQ(0, sysinfo(&si));
 }
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 3a87e88..32b1626 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -857,6 +857,39 @@
   ASSERT_EQ(online_cpus, sysconf(_SC_NPROCESSORS_ONLN));
 }
 
+TEST(UNISTD_TEST, sysconf_SC_ARG_MAX) {
+  // Since Linux 2.6.23, ARG_MAX isn't a constant and depends on RLIMIT_STACK.
+
+  // Get our current limit, and set things up so we restore the limit.
+  rlimit rl;
+  ASSERT_EQ(0, getrlimit(RLIMIT_STACK, &rl));
+  uint64_t original_rlim_cur = rl.rlim_cur;
+  if (rl.rlim_cur == RLIM_INFINITY) {
+    rl.rlim_cur = 8 * 1024 * 1024; // Bionic reports unlimited stacks as 8MiB.
+  }
+  auto guard = make_scope_guard([&rl, original_rlim_cur]() {
+    rl.rlim_cur = original_rlim_cur;
+    ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl));
+  });
+
+  // _SC_ARG_MAX should be 1/4 the stack size.
+  EXPECT_EQ(static_cast<long>(rl.rlim_cur / 4), sysconf(_SC_ARG_MAX));
+
+  // If you have a really small stack, the kernel still guarantees "32 pages" (fs/exec.c).
+  rl.rlim_cur = 1024;
+  rl.rlim_max = RLIM_INFINITY;
+  ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl));
+
+  EXPECT_EQ(static_cast<long>(32 * sysconf(_SC_PAGE_SIZE)), sysconf(_SC_ARG_MAX));
+
+  // With a 128-page stack limit, we know exactly what _SC_ARG_MAX should be...
+  rl.rlim_cur = 128 * sysconf(_SC_PAGE_SIZE);
+  rl.rlim_max = RLIM_INFINITY;
+  ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl));
+
+  EXPECT_EQ(static_cast<long>((128 * sysconf(_SC_PAGE_SIZE)) / 4), sysconf(_SC_ARG_MAX));
+}
+
 TEST(UNISTD_TEST, dup2_same) {
   // POSIX says of dup2:
   // If fildes2 is already a valid open file descriptor ...