Merge "Revert "Revert "Prevent symbols from libgcc from being reexported."""
diff --git a/libc/Android.mk b/libc/Android.mk
index 7febccd..51ca264 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -217,7 +217,7 @@
     bionic/system_properties.cpp \
     bionic/tdestroy.cpp \
     bionic/termios.cpp \
-    bionic/thread_atexit.cpp \
+    bionic/thread_private.cpp \
     bionic/tmpfile.cpp \
     bionic/umount.cpp \
     bionic/unlink.cpp \
@@ -271,10 +271,12 @@
     upstream-netbsd/lib/libc/gen/psignal.c \
     upstream-netbsd/lib/libc/gen/utime.c \
     upstream-netbsd/lib/libc/gen/utmp.c \
+    upstream-netbsd/lib/libc/inet/nsap_addr.c \
     upstream-netbsd/lib/libc/regex/regcomp.c \
     upstream-netbsd/lib/libc/regex/regerror.c \
     upstream-netbsd/lib/libc/regex/regexec.c \
     upstream-netbsd/lib/libc/regex/regfree.c \
+    upstream-netbsd/lib/libc/resolv/mtctxres.c \
     upstream-netbsd/lib/libc/stdlib/bsearch.c \
     upstream-netbsd/lib/libc/stdlib/div.c \
     upstream-netbsd/lib/libc/stdlib/drand48.c \
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 839cfb7..b4c8134 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -285,6 +285,10 @@
 int     sysinfo(struct sysinfo*)  all
 int     personality(unsigned long)  all
 
+ssize_t tee(int, int, size_t, unsigned int)  all
+ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int)  all
+ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int)  all
+
 int epoll_create1(int)  all
 int epoll_ctl(int, int op, int, struct epoll_event*)  all
 int __epoll_pwait:epoll_pwait(int, struct epoll_event*, int, int, const sigset_t*, size_t)  all
diff --git a/libc/arch-arm/syscalls/splice.S b/libc/arch-arm/syscalls/splice.S
new file mode 100644
index 0000000..782ba6c
--- /dev/null
+++ b/libc/arch-arm/syscalls/splice.S
@@ -0,0 +1,22 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(splice)
+    mov     ip, sp
+    stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
+    ldmfd   ip, {r4, r5, r6}
+    ldr     r7, =__NR_splice
+    swi     #0
+    ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(splice)
diff --git a/libc/arch-arm/syscalls/tee.S b/libc/arch-arm/syscalls/tee.S
new file mode 100644
index 0000000..9174617
--- /dev/null
+++ b/libc/arch-arm/syscalls/tee.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(tee)
+    mov     ip, r7
+    ldr     r7, =__NR_tee
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(tee)
diff --git a/libc/arch-arm/syscalls/vmsplice.S b/libc/arch-arm/syscalls/vmsplice.S
new file mode 100644
index 0000000..3b89623
--- /dev/null
+++ b/libc/arch-arm/syscalls/vmsplice.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(vmsplice)
+    mov     ip, r7
+    ldr     r7, =__NR_vmsplice
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(vmsplice)
diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk
index e44ee31..20d9cf1 100644
--- a/libc/arch-arm64/arm64.mk
+++ b/libc/arch-arm64/arm64.mk
@@ -3,7 +3,6 @@
 libc_common_src_files_arm64 := \
     bionic/memchr.c \
     bionic/memrchr.c \
-    bionic/strchr.cpp \
     bionic/strrchr.cpp \
     upstream-freebsd/lib/libc/string/wcscat.c \
     upstream-freebsd/lib/libc/string/wcschr.c \
@@ -12,10 +11,8 @@
     upstream-freebsd/lib/libc/string/wcslen.c \
     upstream-freebsd/lib/libc/string/wcsrchr.c \
     upstream-freebsd/lib/libc/string/wmemcmp.c \
-    upstream-openbsd/lib/libc/string/stpcpy.c \
     upstream-openbsd/lib/libc/string/stpncpy.c \
     upstream-openbsd/lib/libc/string/strcat.c \
-    upstream-openbsd/lib/libc/string/strcpy.c \
     upstream-openbsd/lib/libc/string/strlcat.c \
     upstream-openbsd/lib/libc/string/strlcpy.c \
     upstream-openbsd/lib/libc/string/strncat.c \
diff --git a/libc/arch-arm64/denver64/denver64.mk b/libc/arch-arm64/denver64/denver64.mk
index 36146bf..c6ddb3f 100644
--- a/libc/arch-arm64/denver64/denver64.mk
+++ b/libc/arch-arm64/denver64/denver64.mk
@@ -3,7 +3,10 @@
     arch-arm64/denver64/bionic/memcpy.S \
     arch-arm64/generic/bionic/memmove.S \
     arch-arm64/denver64/bionic/memset.S \
+    arch-arm64/generic/bionic/stpcpy.S \
+    arch-arm64/generic/bionic/strchr.S \
     arch-arm64/generic/bionic/strcmp.S \
+    arch-arm64/generic/bionic/strcpy.S \
     arch-arm64/generic/bionic/strlen.S \
     arch-arm64/generic/bionic/strncmp.S \
     arch-arm64/generic/bionic/strnlen.S \
diff --git a/libc/arch-arm64/generic-neon/generic-neon.mk b/libc/arch-arm64/generic-neon/generic-neon.mk
index 2cbe3cf..f3bde5c 100644
--- a/libc/arch-arm64/generic-neon/generic-neon.mk
+++ b/libc/arch-arm64/generic-neon/generic-neon.mk
@@ -2,7 +2,10 @@
     arch-arm64/generic/bionic/memcmp.S \
     arch-arm64/generic/bionic/memmove.S \
     arch-arm64/generic/bionic/memset.S \
+    arch-arm64/generic/bionic/stpcpy.S \
+    arch-arm64/generic/bionic/strchr.S \
     arch-arm64/generic/bionic/strcmp.S \
+    arch-arm64/generic/bionic/strcpy.S \
     arch-arm64/generic/bionic/strlen.S \
     arch-arm64/generic/bionic/strncmp.S \
     arch-arm64/generic/bionic/strnlen.S \
diff --git a/libc/bionic/thread_atexit.cpp b/libc/arch-arm64/generic/bionic/stpcpy.S
similarity index 73%
copy from libc/bionic/thread_atexit.cpp
copy to libc/arch-arm64/generic/bionic/stpcpy.S
index 68c119d..e4a7993 100644
--- a/libc/bionic/thread_atexit.cpp
+++ b/libc/arch-arm64/generic/bionic/stpcpy.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,22 +25,5 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-
-/* some simple glue used to make the BSD atexit code happy */
-
-#include <pthread.h>
-
-static pthread_mutex_t g_atexit_lock = PTHREAD_MUTEX_INITIALIZER;
-
-__BEGIN_DECLS
-__LIBC_HIDDEN__ void _thread_atexit_lock();
-__LIBC_HIDDEN__ void _thread_atexit_unlock();
-__END_DECLS
-
-void _thread_atexit_lock() {
-  pthread_mutex_lock(&g_atexit_lock);
-}
-
-void _thread_atexit_unlock() {
-  pthread_mutex_unlock(&g_atexit_lock);
-}
+#define STPCPY
+#include "string_copy.S"
diff --git a/libc/arch-arm64/generic/bionic/strchr.S b/libc/arch-arm64/generic/bionic/strchr.S
new file mode 100644
index 0000000..158eaf7
--- /dev/null
+++ b/libc/arch-arm64/generic/bionic/strchr.S
@@ -0,0 +1,153 @@
+/*
+   strchr - find a character in a string
+
+   Copyright (c) 2014, ARM Limited
+   All rights Reserved.
+   Copyright (c) 2014, Linaro Ltd.
+
+   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.
+       * Neither the name of the company nor the names of its contributors
+         may be used to endorse or promote products derived from this
+         software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE 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
+   HOLDER 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.  */
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64
+ * Neon Available.
+ */
+
+#include <private/bionic_asm.h>
+
+/* Arguments and results.  */
+#define srcin		x0
+#define chrin		w1
+
+#define result		x0
+
+#define src		x2
+#define	tmp1		x3
+#define wtmp2		w4
+#define tmp3		x5
+
+#define vrepchr		v0
+#define vdata1		v1
+#define vdata2		v2
+#define vhas_nul1	v3
+#define vhas_nul2	v4
+#define vhas_chr1	v5
+#define vhas_chr2	v6
+#define vrepmask_0	v7
+#define vrepmask_c	v16
+#define vend1		v17
+#define vend2		v18
+
+/* Core algorithm.
+
+   For each 32-byte hunk we calculate a 64-bit syndrome value, with
+   two bits per byte (LSB is always in bits 0 and 1, for both big
+   and little-endian systems).  For each tuple, bit 0 is set iff
+   the relevant byte matched the requested character; bit 1 is set
+   iff the relevant byte matched the NUL end of string (we trigger
+   off bit0 for the special case of looking for NUL).  Since the bits
+   in the syndrome reflect exactly the order in which things occur
+   in the original string a count_trailing_zeros() operation will
+   identify exactly which byte is causing the termination, and why.  */
+
+/* Locals and temporaries.  */
+
+ENTRY(strchr)
+	/* Magic constant 0x40100401 to allow us to identify which lane
+	   matches the requested byte.  Magic constant 0x80200802 used
+	   similarly for NUL termination.  */
+	mov	wtmp2, #0x0401
+	movk	wtmp2, #0x4010, lsl #16
+	dup	vrepchr.16b, chrin
+	bic	src, srcin, #31		/* Work with aligned 32-byte hunks.  */
+	dup	vrepmask_c.4s, wtmp2
+	ands	tmp1, srcin, #31
+	add	vrepmask_0.4s, vrepmask_c.4s, vrepmask_c.4s /* equiv: lsl #1 */
+	b.eq	.Lloop
+
+	/* Input string is not 32-byte aligned.  Rather than forcing
+	   the padding bytes to a safe value, we calculate the syndrome
+	   for all the bytes, but then mask off those bits of the
+	   syndrome that are related to the padding.  */
+	ld1	{vdata1.16b, vdata2.16b}, [src], #32
+	neg	tmp1, tmp1
+	cmeq	vhas_nul1.16b, vdata1.16b, #0
+	cmeq	vhas_chr1.16b, vdata1.16b, vrepchr.16b
+	cmeq	vhas_nul2.16b, vdata2.16b, #0
+	cmeq	vhas_chr2.16b, vdata2.16b, vrepchr.16b
+	and	vhas_nul1.16b, vhas_nul1.16b, vrepmask_0.16b
+	and	vhas_nul2.16b, vhas_nul2.16b, vrepmask_0.16b
+	and	vhas_chr1.16b, vhas_chr1.16b, vrepmask_c.16b
+	and	vhas_chr2.16b, vhas_chr2.16b, vrepmask_c.16b
+	orr	vend1.16b, vhas_nul1.16b, vhas_chr1.16b
+	orr	vend2.16b, vhas_nul2.16b, vhas_chr2.16b
+	lsl	tmp1, tmp1, #1
+	addp	vend1.16b, vend1.16b, vend2.16b		// 256->128
+	mov	tmp3, #~0
+	addp	vend1.16b, vend1.16b, vend2.16b		// 128->64
+	lsr	tmp1, tmp3, tmp1
+
+	mov	tmp3, vend1.2d[0]
+	bic	tmp1, tmp3, tmp1	// Mask padding bits.
+	cbnz	tmp1, .Ltail
+
+.Lloop:
+	ld1	{vdata1.16b, vdata2.16b}, [src], #32
+	cmeq	vhas_nul1.16b, vdata1.16b, #0
+	cmeq	vhas_chr1.16b, vdata1.16b, vrepchr.16b
+	cmeq	vhas_nul2.16b, vdata2.16b, #0
+	cmeq	vhas_chr2.16b, vdata2.16b, vrepchr.16b
+	/* Use a fast check for the termination condition.  */
+	orr	vend1.16b, vhas_nul1.16b, vhas_chr1.16b
+	orr	vend2.16b, vhas_nul2.16b, vhas_chr2.16b
+	orr	vend1.16b, vend1.16b, vend2.16b
+	addp	vend1.2d, vend1.2d, vend1.2d
+	mov	tmp1, vend1.2d[0]
+	cbz	tmp1, .Lloop
+
+	/* Termination condition found.  Now need to establish exactly why
+	   we terminated.  */
+	and	vhas_nul1.16b, vhas_nul1.16b, vrepmask_0.16b
+	and	vhas_nul2.16b, vhas_nul2.16b, vrepmask_0.16b
+	and	vhas_chr1.16b, vhas_chr1.16b, vrepmask_c.16b
+	and	vhas_chr2.16b, vhas_chr2.16b, vrepmask_c.16b
+	orr	vend1.16b, vhas_nul1.16b, vhas_chr1.16b
+	orr	vend2.16b, vhas_nul2.16b, vhas_chr2.16b
+	addp	vend1.16b, vend1.16b, vend2.16b		// 256->128
+	addp	vend1.16b, vend1.16b, vend2.16b		// 128->64
+
+	mov	tmp1, vend1.2d[0]
+.Ltail:
+	/* Count the trailing zeros, by bit reversing...  */
+	rbit	tmp1, tmp1
+	/* Re-bias source.  */
+	sub	src, src, #32
+	clz	tmp1, tmp1	/* And counting the leading zeros.  */
+	/* Tmp1 is even if the target charager was found first.  Otherwise
+	   we've found the end of string and we weren't looking for NUL.  */
+	tst	tmp1, #1
+	add	result, src, tmp1, lsr #1
+	csel	result, result, xzr, eq
+	ret
+END(strchr)
diff --git a/libc/bionic/thread_atexit.cpp b/libc/arch-arm64/generic/bionic/strcpy.S
similarity index 73%
copy from libc/bionic/thread_atexit.cpp
copy to libc/arch-arm64/generic/bionic/strcpy.S
index 68c119d..260c321 100644
--- a/libc/bionic/thread_atexit.cpp
+++ b/libc/arch-arm64/generic/bionic/strcpy.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,22 +25,5 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-
-/* some simple glue used to make the BSD atexit code happy */
-
-#include <pthread.h>
-
-static pthread_mutex_t g_atexit_lock = PTHREAD_MUTEX_INITIALIZER;
-
-__BEGIN_DECLS
-__LIBC_HIDDEN__ void _thread_atexit_lock();
-__LIBC_HIDDEN__ void _thread_atexit_unlock();
-__END_DECLS
-
-void _thread_atexit_lock() {
-  pthread_mutex_lock(&g_atexit_lock);
-}
-
-void _thread_atexit_unlock() {
-  pthread_mutex_unlock(&g_atexit_lock);
-}
+#define STRCPY
+#include "string_copy.S"
diff --git a/libc/arch-arm64/generic/bionic/string_copy.S b/libc/arch-arm64/generic/bionic/string_copy.S
new file mode 100644
index 0000000..3d753b6
--- /dev/null
+++ b/libc/arch-arm64/generic/bionic/string_copy.S
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+/* Copyright (c) 2014, Linaro Limited
+   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.
+       * Neither the name of the Linaro nor the
+         names of its contributors may be used to endorse or promote products
+         derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE 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
+   HOLDER 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.
+*/
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64
+ */
+
+#if !defined(STPCPY) && !defined(STRCPY)
+#error "Either STPCPY or STRCPY must be defined."
+#endif
+
+#include <private/bionic_asm.h>
+
+/* Arguments and results.  */
+#if defined(STPCPY)
+#define dst         x0
+#elif defined(STRCPY)
+#define dstin       x0
+#endif
+#define src         x1
+
+/* Locals and temporaries.  */
+#if defined(STRCPY)
+#define dst         x2
+#endif
+#define data1       x3
+#define data1_w     w3
+#define data2       x4
+#define data2_w     w4
+#define has_nul1    x5
+#define has_nul1_w  w5
+#define has_nul2    x6
+#define tmp1        x7
+#define tmp2        x8
+#define tmp3        x9
+#define tmp4        x10
+#define zeroones    x11
+#define zeroones_w  w11
+#define pos         x12
+
+#define REP8_01 0x0101010101010101
+#define REP8_7f 0x7f7f7f7f7f7f7f7f
+#define REP8_80 0x8080808080808080
+
+#if defined(STPCPY)
+ENTRY(stpcpy)
+#elif defined(STRCPY)
+ENTRY(strcpy)
+#endif
+    mov     zeroones, #REP8_01
+#if defined(STRCPY)
+    mov     dst, dstin
+#endif
+    ands    tmp1, src, #15
+    b.ne    .Lmisaligned
+    // NUL detection works on the principle that (X - 1) & (~X) & 0x80
+    // (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
+    // can be done in parallel across the entire word.
+    // The inner loop deals with two Dwords at a time.  This has a
+    // slightly higher start-up cost, but we should win quite quickly,
+    // especially on cores with a high number of issue slots per
+    // cycle, as we get much better parallelism out of the operations.
+.Lloop:
+    ldp     data1, data2, [src], #16
+    sub     tmp1, data1, zeroones
+    orr     tmp2, data1, #REP8_7f
+    bic     has_nul1, tmp1, tmp2
+    cbnz    has_nul1, .Lnul_in_data1
+    sub     tmp3, data2, zeroones
+    orr     tmp4, data2, #REP8_7f
+    bic     has_nul2, tmp3, tmp4
+    cbnz    has_nul2, .Lnul_in_data2
+    // No NUL in either register, copy it in a single instruction.
+    stp     data1, data2, [dst], #16
+    b       .Lloop
+
+.Lnul_in_data1:
+    rev     has_nul1, has_nul1
+    clz     pos, has_nul1
+    add     tmp1, pos, #0x8
+
+    tbz     tmp1, #6, 1f
+#if defined(STPCPY)
+    str     data1, [dst], #7
+#elif defined(STRCPY)
+    str     data1, [dst]
+#endif
+    ret
+1:
+    tbz     tmp1, #5, 1f
+    str     data1_w, [dst], #4
+    lsr     data1, data1, #32
+1:
+    tbz     tmp1, #4, 1f
+    strh    data1_w, [dst], #2
+    lsr     data1, data1, #16
+1:
+    tbz     tmp1, #3, 1f
+    strb    data1_w, [dst]
+#if defined(STPCPY)
+    ret
+#endif
+1:
+#if defined(STPCPY)
+    // Back up one so that dst points to the '\0' string terminator.
+    sub     dst, dst, #1
+#endif
+    ret
+
+.Lnul_in_data2:
+    str     data1, [dst], #8
+    rev     has_nul2, has_nul2
+    clz     pos, has_nul2
+    add     tmp1, pos, #0x8
+
+    tbz     tmp1, #6, 1f
+#if defined(STPCPY)
+    str     data2, [dst], #7
+#elif defined(STRCPY)
+    str     data2, [dst]
+#endif
+    ret
+1:
+    tbz     tmp1, #5, 1f
+    str     data2_w, [dst], #4
+    lsr     data2, data2, #32
+1:
+    tbz     tmp1, #4, 1f
+    strh    data2_w, [dst], #2
+    lsr     data2, data2, #16
+1:
+    tbz     tmp1, #3, 1f
+    strb    data2_w, [dst]
+#if defined(STPCPY)
+    ret
+#endif
+1:
+#if defined(STPCPY)
+    // Back up one so that dst points to the '\0' string terminator.
+    sub     dst, dst, #1
+#endif
+    ret
+
+.Lmisaligned:
+    tbz     src, #0, 1f
+    ldrb    data1_w, [src], #1
+    strb    data1_w, [dst], #1
+    cbnz    data1_w, 1f
+#if defined(STPCPY)
+    // Back up one so that dst points to the '\0' string terminator.
+    sub     dst, dst, #1
+#endif
+    ret
+1:
+    tbz     src, #1, 1f
+    ldrb    data1_w, [src], #1
+    strb    data1_w, [dst], #1
+    cbz     data1_w, .Ldone
+    ldrb    data2_w, [src], #1
+    strb    data2_w, [dst], #1
+    cbnz    data2_w, 1f
+.Ldone:
+#if defined(STPCPY)
+    // Back up one so that dst points to the '\0' string terminator.
+    sub     dst, dst, #1
+#endif
+    ret
+1:
+    tbz     src, #2, 1f
+    ldr     data1_w, [src], #4
+    // Check for a zero.
+    sub     has_nul1_w, data1_w, zeroones_w
+    bic     has_nul1_w, has_nul1_w, data1_w
+    ands    has_nul1_w, has_nul1_w, #0x80808080
+    b.ne    .Lnul_in_data1
+    str     data1_w, [dst], #4
+1:
+    tbz     src, #3, .Lloop
+    ldr     data1, [src], #8
+    // Check for a zero.
+    sub     tmp1, data1, zeroones
+    orr     tmp2, data1, #REP8_7f
+    bics    has_nul1, tmp1, tmp2
+    b.ne    .Lnul_in_data1
+    str     data1, [dst], #8
+    b       .Lloop
+#if defined(STPCPY)
+END(stpcpy)
+#elif defined(STRCPY)
+END(strcpy)
+#endif
diff --git a/libc/arch-arm64/generic/generic.mk b/libc/arch-arm64/generic/generic.mk
index e10cf66..878dcdf 100644
--- a/libc/arch-arm64/generic/generic.mk
+++ b/libc/arch-arm64/generic/generic.mk
@@ -3,7 +3,10 @@
     arch-arm64/generic/bionic/memcpy.S \
     arch-arm64/generic/bionic/memmove.S \
     arch-arm64/generic/bionic/memset.S \
+    arch-arm64/generic/bionic/stpcpy.S \
+    arch-arm64/generic/bionic/strchr.S \
     arch-arm64/generic/bionic/strcmp.S \
+    arch-arm64/generic/bionic/strcpy.S \
     arch-arm64/generic/bionic/strlen.S \
     arch-arm64/generic/bionic/strncmp.S \
     arch-arm64/generic/bionic/strnlen.S \
diff --git a/libc/arch-arm64/syscalls/splice.S b/libc/arch-arm64/syscalls/splice.S
new file mode 100644
index 0000000..103805a
--- /dev/null
+++ b/libc/arch-arm64/syscalls/splice.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(splice)
+    mov     x8, __NR_splice
+    svc     #0
+
+    cmn     x0, #(MAX_ERRNO + 1)
+    cneg    x0, x0, hi
+    b.hi    __set_errno
+
+    ret
+END(splice)
diff --git a/libc/arch-arm64/syscalls/tee.S b/libc/arch-arm64/syscalls/tee.S
new file mode 100644
index 0000000..d730076
--- /dev/null
+++ b/libc/arch-arm64/syscalls/tee.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(tee)
+    mov     x8, __NR_tee
+    svc     #0
+
+    cmn     x0, #(MAX_ERRNO + 1)
+    cneg    x0, x0, hi
+    b.hi    __set_errno
+
+    ret
+END(tee)
diff --git a/libc/arch-arm64/syscalls/vmsplice.S b/libc/arch-arm64/syscalls/vmsplice.S
new file mode 100644
index 0000000..b4bec3f
--- /dev/null
+++ b/libc/arch-arm64/syscalls/vmsplice.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(vmsplice)
+    mov     x8, __NR_vmsplice
+    svc     #0
+
+    cmn     x0, #(MAX_ERRNO + 1)
+    cneg    x0, x0, hi
+    b.hi    __set_errno
+
+    ret
+END(vmsplice)
diff --git a/libc/arch-mips/syscalls/splice.S b/libc/arch-mips/syscalls/splice.S
new file mode 100644
index 0000000..d344a6c
--- /dev/null
+++ b/libc/arch-mips/syscalls/splice.S
@@ -0,0 +1,19 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(splice)
+    .set noreorder
+    .cpload t9
+    li v0, __NR_splice
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    la t9,__set_errno
+    j t9
+    nop
+    .set reorder
+END(splice)
diff --git a/libc/arch-mips/syscalls/tee.S b/libc/arch-mips/syscalls/tee.S
new file mode 100644
index 0000000..e51732d
--- /dev/null
+++ b/libc/arch-mips/syscalls/tee.S
@@ -0,0 +1,19 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(tee)
+    .set noreorder
+    .cpload t9
+    li v0, __NR_tee
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    la t9,__set_errno
+    j t9
+    nop
+    .set reorder
+END(tee)
diff --git a/libc/arch-mips/syscalls/vmsplice.S b/libc/arch-mips/syscalls/vmsplice.S
new file mode 100644
index 0000000..24da515
--- /dev/null
+++ b/libc/arch-mips/syscalls/vmsplice.S
@@ -0,0 +1,19 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(vmsplice)
+    .set noreorder
+    .cpload t9
+    li v0, __NR_vmsplice
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    la t9,__set_errno
+    j t9
+    nop
+    .set reorder
+END(vmsplice)
diff --git a/libc/arch-mips64/syscalls/splice.S b/libc/arch-mips64/syscalls/splice.S
new file mode 100644
index 0000000..d626904
--- /dev/null
+++ b/libc/arch-mips64/syscalls/splice.S
@@ -0,0 +1,25 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(splice)
+    .set push
+    .set noreorder
+    li v0, __NR_splice
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    move t0, ra
+    bal     2f
+    nop
+2:
+    .cpsetup ra, t1, 2b
+    LA t9,__set_errno
+    .cpreturn
+    j t9
+    move ra, t0
+    .set pop
+END(splice)
diff --git a/libc/arch-mips64/syscalls/tee.S b/libc/arch-mips64/syscalls/tee.S
new file mode 100644
index 0000000..429700c
--- /dev/null
+++ b/libc/arch-mips64/syscalls/tee.S
@@ -0,0 +1,25 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(tee)
+    .set push
+    .set noreorder
+    li v0, __NR_tee
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    move t0, ra
+    bal     2f
+    nop
+2:
+    .cpsetup ra, t1, 2b
+    LA t9,__set_errno
+    .cpreturn
+    j t9
+    move ra, t0
+    .set pop
+END(tee)
diff --git a/libc/arch-mips64/syscalls/vmsplice.S b/libc/arch-mips64/syscalls/vmsplice.S
new file mode 100644
index 0000000..aa03585
--- /dev/null
+++ b/libc/arch-mips64/syscalls/vmsplice.S
@@ -0,0 +1,25 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(vmsplice)
+    .set push
+    .set noreorder
+    li v0, __NR_vmsplice
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    move t0, ra
+    bal     2f
+    nop
+2:
+    .cpsetup ra, t1, 2b
+    LA t9,__set_errno
+    .cpreturn
+    j t9
+    move ra, t0
+    .set pop
+END(vmsplice)
diff --git a/libc/arch-x86/syscalls/splice.S b/libc/arch-x86/syscalls/splice.S
new file mode 100644
index 0000000..46e2312
--- /dev/null
+++ b/libc/arch-x86/syscalls/splice.S
@@ -0,0 +1,46 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(splice)
+    pushl   %ebx
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset ebx, 0
+    pushl   %ecx
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset ecx, 0
+    pushl   %edx
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset edx, 0
+    pushl   %esi
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset esi, 0
+    pushl   %edi
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset edi, 0
+    pushl   %ebp
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset ebp, 0
+    mov     28(%esp), %ebx
+    mov     32(%esp), %ecx
+    mov     36(%esp), %edx
+    mov     40(%esp), %esi
+    mov     44(%esp), %edi
+    mov     48(%esp), %ebp
+    movl    $__NR_splice, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno
+    addl    $4, %esp
+1:
+    popl    %ebp
+    popl    %edi
+    popl    %esi
+    popl    %edx
+    popl    %ecx
+    popl    %ebx
+    ret
+END(splice)
diff --git a/libc/arch-x86/syscalls/tee.S b/libc/arch-x86/syscalls/tee.S
new file mode 100644
index 0000000..9422660
--- /dev/null
+++ b/libc/arch-x86/syscalls/tee.S
@@ -0,0 +1,36 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(tee)
+    pushl   %ebx
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset ebx, 0
+    pushl   %ecx
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset ecx, 0
+    pushl   %edx
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset edx, 0
+    pushl   %esi
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset esi, 0
+    mov     20(%esp), %ebx
+    mov     24(%esp), %ecx
+    mov     28(%esp), %edx
+    mov     32(%esp), %esi
+    movl    $__NR_tee, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno
+    addl    $4, %esp
+1:
+    popl    %esi
+    popl    %edx
+    popl    %ecx
+    popl    %ebx
+    ret
+END(tee)
diff --git a/libc/arch-x86/syscalls/vmsplice.S b/libc/arch-x86/syscalls/vmsplice.S
new file mode 100644
index 0000000..2afba60
--- /dev/null
+++ b/libc/arch-x86/syscalls/vmsplice.S
@@ -0,0 +1,36 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(vmsplice)
+    pushl   %ebx
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset ebx, 0
+    pushl   %ecx
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset ecx, 0
+    pushl   %edx
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset edx, 0
+    pushl   %esi
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset esi, 0
+    mov     20(%esp), %ebx
+    mov     24(%esp), %ecx
+    mov     28(%esp), %edx
+    mov     32(%esp), %esi
+    movl    $__NR_vmsplice, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno
+    addl    $4, %esp
+1:
+    popl    %esi
+    popl    %edx
+    popl    %ecx
+    popl    %ebx
+    ret
+END(vmsplice)
diff --git a/libc/arch-x86_64/syscalls/splice.S b/libc/arch-x86_64/syscalls/splice.S
new file mode 100644
index 0000000..3c245a5
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/splice.S
@@ -0,0 +1,16 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(splice)
+    movq    %rcx, %r10
+    movl    $__NR_splice, %eax
+    syscall
+    cmpq    $-MAX_ERRNO, %rax
+    jb      1f
+    negl    %eax
+    movl    %eax, %edi
+    call    __set_errno
+1:
+    ret
+END(splice)
diff --git a/libc/arch-x86_64/syscalls/tee.S b/libc/arch-x86_64/syscalls/tee.S
new file mode 100644
index 0000000..ad5698c
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/tee.S
@@ -0,0 +1,16 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(tee)
+    movq    %rcx, %r10
+    movl    $__NR_tee, %eax
+    syscall
+    cmpq    $-MAX_ERRNO, %rax
+    jb      1f
+    negl    %eax
+    movl    %eax, %edi
+    call    __set_errno
+1:
+    ret
+END(tee)
diff --git a/libc/arch-x86_64/syscalls/vmsplice.S b/libc/arch-x86_64/syscalls/vmsplice.S
new file mode 100644
index 0000000..cc94cc6
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/vmsplice.S
@@ -0,0 +1,16 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(vmsplice)
+    movq    %rcx, %r10
+    movl    $__NR_vmsplice, %eax
+    syscall
+    cmpq    $-MAX_ERRNO, %rax
+    jb      1f
+    negl    %eax
+    movl    %eax, %edi
+    call    __set_errno
+1:
+    ret
+END(vmsplice)
diff --git a/libc/bionic/arc4random.c b/libc/bionic/arc4random.c
index 687030b..9bdf341 100644
--- a/libc/bionic/arc4random.c
+++ b/libc/bionic/arc4random.c
@@ -1,8 +1,9 @@
-/*      $OpenBSD: arc4random.c,v 1.19 2008/06/04 00:50:23 djm Exp $        */
+/*	$OpenBSD: arc4random.c,v 1.33 2014/06/13 18:58:58 deraadt Exp $	*/
 
 /*
  * Copyright (c) 1996, David Mazieres <dm@uun.org>
  * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -18,214 +19,236 @@
  */
 
 /*
- * Arc4 random number generator for OpenBSD.
- *
- * This code is derived from section 17.1 of Applied Cryptography,
- * second edition, which describes a stream cipher allegedly
- * compatible with RSA Labs "RC4" cipher (the actual description of
- * which is a trade secret).  The same algorithm is used as a stream
- * cipher called "arcfour" in Tatu Ylonen's ssh package.
- *
- * Here the stream cipher has been modified always to include the time
- * when initializing the state.  That makes it impossible to
- * regenerate the same random sequence twice, so this can't be used
- * for encryption, but will generate good random numbers.
- *
- * RC4 is a registered trademark of RSA Laboratories.
+ * ChaCha based random number generator for OpenBSD.
  */
 
 #include <fcntl.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/time.h>
+#include <sys/mman.h>
+
+#if defined(__ANDROID__)
+#include <sys/stat.h>
+#include <linux/random.h>
+#include "private/libc_logging.h"
 #include "private/thread_private.h"
 
-/* BIONIC-BEGIN */
-/* this lock should protect the global variables in this file */
-static pthread_mutex_t  _arc4_lock = PTHREAD_MUTEX_INITIALIZER;
-#define  _ARC4_LOCK()      pthread_mutex_lock(&_arc4_lock)
-#define  _ARC4_UNLOCK()    pthread_mutex_unlock(&_arc4_lock)
-/* BIONIC-END */
+#define explicit_bzero(p, s) memset(p, 0, s)
+
+#undef MAP_ANON
+#define MAP_ANON (MAP_PRIVATE | MAP_ANONYMOUS)
+
+/*
+ * XXX Should be replaced with a proper entropy measure.
+ */
+static int
+gotdata(u_char *buf, size_t len)
+{
+	char	any_set = 0;
+	size_t	i;
+
+	for (i = 0; i < len; ++i)
+		any_set |= buf[i];
+	if (any_set == 0)
+		return -1;
+	return 0;
+}
+
+static int
+getentropy/*_urandom*/(u_char *buf, size_t len)
+{
+	int save_errno = errno;
+
+	int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOFOLLOW, 0));
+	if (fd == -1) {
+		__libc_fatal("getentropy_urandom failed to open \"/dev/urandom\": %s",
+				strerror(errno));
+	}
+
+	/* Lightly verify that the device node looks sane */
+	struct stat st;
+	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
+		__libc_fatal("getentropy_urandom failed to fstat \"/dev/urandom\": %s",
+				strerror(errno));
+	}
+	int cnt;
+	if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) {
+		__libc_fatal("getentropy_urandom failed to ioctl \"/dev/urandom\": %s",
+				strerror(errno));
+	}
+	for (size_t i = 0; i < len; ) {
+		size_t wanted = len - i;
+		ssize_t ret = TEMP_FAILURE_RETRY(read(fd, buf + i, wanted));
+
+		if (ret == -1) {
+			__libc_fatal("getentropy_urandom failed to read \"/dev/urandom\": %s",
+					strerror(errno));
+		}
+		i += ret;
+	}
+	close(fd);
+	if (gotdata(buf, len) == -1) {
+		__libc_fatal("getentropy_urandom failed to get enough entropy: %s",
+				strerror(errno));
+	}
+
+	errno = save_errno;
+	return 0;
+}
+#endif /* __ANDROID__ */
+
+#define KEYSTREAM_ONLY
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#include "../upstream-openbsd/lib/libc/crypt/chacha_private.h"
+#pragma GCC diagnostic pop
 
 #ifdef __GNUC__
 #define inline __inline
-#else                           /* !__GNUC__ */
+#else				/* !__GNUC__ */
 #define inline
-#endif                          /* !__GNUC__ */
+#endif				/* !__GNUC__ */
 
-struct arc4_stream {
-        u_int8_t i;
-        u_int8_t j;
-        u_int8_t s[256];
-};
-
+#define KEYSZ	32
+#define IVSZ	8
+#define BLOCKSZ	64
+#define RSBUFSZ	(16*BLOCKSZ)
 static int rs_initialized;
-static struct arc4_stream rs;
-static pid_t arc4_stir_pid;
-static int arc4_count;
+static pid_t rs_stir_pid;
+static chacha_ctx *rs;		/* chacha context for random keystream */
+static u_char *rs_buf;		/* keystream blocks */
+static size_t rs_have;		/* valid bytes at end of rs_buf */
+static size_t rs_count;		/* bytes till reseed */
 
-static inline u_int8_t arc4_getbyte(void);
+static inline void _rs_rekey(u_char *dat, size_t datlen);
 
 static inline void
-arc4_init(void)
+_rs_init(u_char *buf, size_t n)
 {
-        int     n;
+	if (n < KEYSZ + IVSZ)
+		return;
 
-        for (n = 0; n < 256; n++)
-                rs.s[n] = n;
-        rs.i = 0;
-        rs.j = 0;
-}
+	if (rs == NULL && (rs = mmap(NULL, sizeof(*rs), PROT_READ|PROT_WRITE,
+	    MAP_ANON, -1, 0)) == MAP_FAILED)
+		abort();
+	if (rs_buf == NULL && (rs_buf = mmap(NULL, RSBUFSZ, PROT_READ|PROT_WRITE,
+	    MAP_ANON, -1, 0)) == MAP_FAILED)
+		abort();
 
-static inline void
-arc4_addrandom(u_char *dat, int datlen)
-{
-        int     n;
-        u_int8_t si;
-
-        rs.i--;
-        for (n = 0; n < 256; n++) {
-                rs.i = (rs.i + 1);
-                si = rs.s[rs.i];
-                rs.j = (rs.j + si + dat[n % datlen]);
-                rs.s[rs.i] = rs.s[rs.j];
-                rs.s[rs.j] = si;
-        }
-        rs.j = rs.i;
+	chacha_keysetup(rs, buf, KEYSZ * 8, 0);
+	chacha_ivsetup(rs, buf + KEYSZ);
 }
 
 static void
-arc4_stir(void)
+_rs_stir(void)
 {
-#if 1  /* BIONIC-BEGIN */
-	int     i, fd;
-	union {
-		struct timeval tv;
-		u_int rnd[128 / sizeof(u_int)];
-	}       rdat;
-	int	n;
+	u_char rnd[KEYSZ + IVSZ];
 
-        if (!rs_initialized) {
-                arc4_init();
-                rs_initialized = 1;
-        }
+	/* XXX */
+	(void) getentropy(rnd, sizeof rnd);
 
-	fd = open("/dev/urandom", O_RDONLY);
-	if (fd != -1) {
-		read(fd, rdat.rnd, sizeof(rdat.rnd));
-		close(fd);
-	}
-        else
-        {
-	    /* fd < 0 ?  Ah, what the heck. We'll just take
-	     * whatever was on the stack. just add a little more
-             * time-based randomness though
-             */
-            gettimeofday(&rdat.tv, NULL);
-        }
+	if (!rs_initialized) {
+		rs_initialized = 1;
+		_rs_init(rnd, sizeof(rnd));
+	} else
+		_rs_rekey(rnd, sizeof(rnd));
+	explicit_bzero(rnd, sizeof(rnd));
 
-        arc4_stir_pid = getpid();
-	arc4_addrandom((void *) &rdat, sizeof(rdat));
-#else  /* BIONIC-END */
-        int     i, mib[2];
-        size_t        len;
-        u_char rnd[128];
+	/* invalidate rs_buf */
+	rs_have = 0;
+	memset(rs_buf, 0, RSBUFSZ);
 
-        if (!rs_initialized) {
-                arc4_init();
-                rs_initialized = 1;
-        }
+	rs_count = 1600000;
+}
 
-        mib[0] = CTL_KERN;
-        mib[1] = KERN_ARND;
+static inline void
+_rs_stir_if_needed(size_t len)
+{
+	pid_t pid = getpid();
 
-        len = sizeof(rnd);
-        sysctl(mib, 2, rnd, &len, NULL, 0);
+	if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) {
+		rs_stir_pid = pid;
+		_rs_stir();
+	} else
+		rs_count -= len;
+}
 
-        arc4_stir_pid = getpid();
-        arc4_addrandom(rnd, sizeof(rnd));
+static inline void
+_rs_rekey(u_char *dat, size_t datlen)
+{
+#ifndef KEYSTREAM_ONLY
+	memset(rs_buf, 0,RSBUFSZ);
 #endif
-        /*
-         * Discard early keystream, as per recommendations in:
-         * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
-         */
-        for (i = 0; i < 256; i++)
-                (void)arc4_getbyte();
-        arc4_count = 1600000;
+	/* fill rs_buf with the keystream */
+	chacha_encrypt_bytes(rs, rs_buf, rs_buf, RSBUFSZ);
+	/* mix in optional user provided data */
+	if (dat) {
+		size_t i, m;
+
+		m = MIN(datlen, KEYSZ + IVSZ);
+		for (i = 0; i < m; i++)
+			rs_buf[i] ^= dat[i];
+	}
+	/* immediately reinit for backtracking resistance */
+	_rs_init(rs_buf, KEYSZ + IVSZ);
+	memset(rs_buf, 0, KEYSZ + IVSZ);
+	rs_have = RSBUFSZ - KEYSZ - IVSZ;
 }
 
-static inline u_int8_t
-arc4_getbyte(void)
+static inline void
+_rs_random_buf(void *_buf, size_t n)
 {
-        u_int8_t si, sj;
+	u_char *buf = (u_char *)_buf;
+	size_t m;
 
-        rs.i = (rs.i + 1);
-        si = rs.s[rs.i];
-        rs.j = (rs.j + si);
-        sj = rs.s[rs.j];
-        rs.s[rs.i] = sj;
-        rs.s[rs.j] = si;
-        return (rs.s[(si + sj) & 0xff]);
+	_rs_stir_if_needed(n);
+	while (n > 0) {
+		if (rs_have > 0) {
+			m = MIN(n, rs_have);
+			memcpy(buf, rs_buf + RSBUFSZ - rs_have, m);
+			memset(rs_buf + RSBUFSZ - rs_have, 0, m);
+			buf += m;
+			n -= m;
+			rs_have -= m;
+		}
+		if (rs_have == 0)
+			_rs_rekey(NULL, 0);
+	}
 }
 
-static inline u_int32_t
-arc4_getword(void)
+static inline void
+_rs_random_u32(u_int32_t *val)
 {
-        u_int32_t val;
-        val = arc4_getbyte() << 24;
-        val |= arc4_getbyte() << 16;
-        val |= arc4_getbyte() << 8;
-        val |= arc4_getbyte();
-        return val;
-}
-
-void
-arc4random_stir(void)
-{
-        _ARC4_LOCK();
-        arc4_stir();
-        _ARC4_UNLOCK();
-}
-
-void
-arc4random_addrandom(u_char *dat, int datlen)
-{
-        _ARC4_LOCK();
-        if (!rs_initialized)
-                arc4_stir();
-        arc4_addrandom(dat, datlen);
-        _ARC4_UNLOCK();
+	_rs_stir_if_needed(sizeof(*val));
+	if (rs_have < sizeof(*val))
+		_rs_rekey(NULL, 0);
+	memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val));
+	memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val));
+	rs_have -= sizeof(*val);
 }
 
 u_int32_t
 arc4random(void)
 {
-        u_int32_t val;
-        _ARC4_LOCK();
-        arc4_count -= 4;
-        if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != getpid())
-                arc4_stir();
-        val = arc4_getword();
-        _ARC4_UNLOCK();
-        return val;
+	u_int32_t val;
+
+	_ARC4_LOCK();
+	_rs_random_u32(&val);
+	_ARC4_UNLOCK();
+	return val;
 }
 
 void
-arc4random_buf(void *_buf, size_t n)
+arc4random_buf(void *buf, size_t n)
 {
-        u_char *buf = (u_char *)_buf;
-        _ARC4_LOCK();
-        if (!rs_initialized || arc4_stir_pid != getpid())
-                arc4_stir();
-        while (n--) {
-                if (--arc4_count <= 0)
-                        arc4_stir();
-                buf[n] = arc4_getbyte();
-        }
-        _ARC4_UNLOCK();
+	_ARC4_LOCK();
+	_rs_random_buf(buf, n);
+	_ARC4_UNLOCK();
 }
 
 /*
@@ -241,55 +264,25 @@
 u_int32_t
 arc4random_uniform(u_int32_t upper_bound)
 {
-        u_int32_t r, min;
+	u_int32_t r, min;
 
-        if (upper_bound < 2)
-                return 0;
+	if (upper_bound < 2)
+		return 0;
 
-#if (ULONG_MAX > 0xffffffffUL)
-        min = 0x100000000UL % upper_bound;
-#else
-        /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
-        if (upper_bound > 0x80000000)
-                min = 1 + ~upper_bound;                /* 2**32 - upper_bound */
-        else {
-                /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
-                min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
-        }
-#endif
+	/* 2**32 % x == (2**32 - x) % x */
+	min = -upper_bound % upper_bound;
 
-        /*
-         * This could theoretically loop forever but each retry has
-         * p > 0.5 (worst case, usually far better) of selecting a
-         * number inside the range we need, so it should rarely need
-         * to re-roll.
-         */
-        for (;;) {
-                r = arc4random();
-                if (r >= min)
-                        break;
-        }
+	/*
+	 * This could theoretically loop forever but each retry has
+	 * p > 0.5 (worst case, usually far better) of selecting a
+	 * number inside the range we need, so it should rarely need
+	 * to re-roll.
+	 */
+	for (;;) {
+		r = arc4random();
+		if (r >= min)
+			break;
+	}
 
-        return r % upper_bound;
+	return r % upper_bound;
 }
-
-#if 0
-/*-------- Test code for i386 --------*/
-#include <stdio.h>
-#include <machine/pctr.h>
-int
-main(int argc, char **argv)
-{
-        const int iter = 1000000;
-        int     i;
-        pctrval v;
-
-        v = rdtsc();
-        for (i = 0; i < iter; i++)
-                arc4random();
-        v = rdtsc() - v;
-        v /= iter;
-
-        printf("%qd cycles\n", v);
-}
-#endif
diff --git a/libc/bionic/clone.cpp b/libc/bionic/clone.cpp
index 001e245..0a0fdd5 100644
--- a/libc/bionic/clone.cpp
+++ b/libc/bionic/clone.cpp
@@ -31,6 +31,8 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
+#include "pthread_internal.h"
+
 extern "C" pid_t __bionic_clone(uint32_t flags, void* child_stack, int* parent_tid, void* tls, int* child_tid, int (*fn)(void*), void* arg);
 extern "C" __noreturn void __exit(int status);
 
@@ -64,5 +66,18 @@
   child_stack_addr &= ~0xf;
   child_stack = reinterpret_cast<void*>(child_stack_addr);
 
-  return __bionic_clone(flags, child_stack, parent_tid, new_tls, child_tid, fn, arg);
+  // Remember the parent pid and invalidate the cached value while we clone.
+  pthread_internal_t* self = __get_thread();
+  pid_t parent_pid = self->invalidate_cached_pid();
+
+  // Actually do the clone.
+  int clone_result = __bionic_clone(flags, child_stack, parent_tid, new_tls, child_tid, fn, arg);
+
+  // We're the parent, so put our known pid back in place.
+  // We leave the child without a cached pid, but:
+  // 1. pthread_create gives its children their own pthread_internal_t with the correct pid.
+  // 2. fork makes a clone system call directly.
+  // If any other cases become important, we could use a double trampoline like __pthread_start.
+  self->set_cached_pid(parent_pid);
+  return clone_result;
 }
diff --git a/libc/bionic/cmsg_nxthdr.cpp b/libc/bionic/cmsg_nxthdr.cpp
index 6f0a47c..8a2b33e 100644
--- a/libc/bionic/cmsg_nxthdr.cpp
+++ b/libc/bionic/cmsg_nxthdr.cpp
@@ -28,7 +28,7 @@
 
 #include <sys/socket.h>
 
-cmsghdr* cmsg_nxthdr(msghdr* msg, cmsghdr* cmsg) {
+cmsghdr* __cmsg_nxthdr(msghdr* msg, cmsghdr* cmsg) {
   cmsghdr* ptr;
   ptr = reinterpret_cast<cmsghdr*>(reinterpret_cast<char*>(cmsg) + CMSG_ALIGN(cmsg->cmsg_len));
   size_t len = reinterpret_cast<char*>(ptr+1) - reinterpret_cast<char*>(msg->msg_control);
@@ -37,3 +37,6 @@
   }
   return ptr;
 }
+
+// TODO: remove after NDK refresh.
+__weak_alias(cmsg_nxthdr, __cmsg_nxthdr);
diff --git a/libc/bionic/if_indextoname.c b/libc/bionic/if_indextoname.c
index dc08b28..f0db512 100644
--- a/libc/bionic/if_indextoname.c
+++ b/libc/bionic/if_indextoname.c
@@ -41,7 +41,6 @@
 char*
 if_indextoname(unsigned ifindex, char *ifname)
 {
-    int index;
     int ctl_sock;
     struct ifreq ifr;
     char*  ret = NULL;
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index 8966a5f..8b3d3f1 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -619,7 +619,8 @@
   BufferOutputStream os(msg, sizeof(msg));
   out_vformat(os, format, args);
 
-  // TODO: log to stderr for the benefit of "adb shell" users.
+  // log to stderr for the benefit of "adb shell" users.
+  write(2, msg, strlen(msg));
 
   // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
   __libc_write_log(ANDROID_LOG_FATAL, "libc", msg);
diff --git a/libc/bionic/thread_atexit.cpp b/libc/bionic/thread_private.cpp
similarity index 84%
rename from libc/bionic/thread_atexit.cpp
rename to libc/bionic/thread_private.cpp
index 68c119d..1c04019 100644
--- a/libc/bionic/thread_atexit.cpp
+++ b/libc/bionic/thread_private.cpp
@@ -26,17 +26,13 @@
  * SUCH DAMAGE.
  */
 
-/* some simple glue used to make the BSD atexit code happy */
-
 #include <pthread.h>
+#include "private/thread_private.h"
+
+// Some simple glue used to make BSD code thread-safe.
 
 static pthread_mutex_t g_atexit_lock = PTHREAD_MUTEX_INITIALIZER;
 
-__BEGIN_DECLS
-__LIBC_HIDDEN__ void _thread_atexit_lock();
-__LIBC_HIDDEN__ void _thread_atexit_unlock();
-__END_DECLS
-
 void _thread_atexit_lock() {
   pthread_mutex_lock(&g_atexit_lock);
 }
@@ -44,3 +40,13 @@
 void _thread_atexit_unlock() {
   pthread_mutex_unlock(&g_atexit_lock);
 }
+
+static pthread_mutex_t g_arc4_lock = PTHREAD_MUTEX_INITIALIZER;
+
+void _thread_arc4_lock() {
+  pthread_mutex_lock(&g_arc4_lock);
+}
+
+void _thread_arc4_unlock() {
+  pthread_mutex_unlock(&g_arc4_lock);
+}
diff --git a/libc/bionic/time64.c b/libc/bionic/time64.c
index 7163b34..62ee903 100644
--- a/libc/bionic/time64.c
+++ b/libc/bionic/time64.c
@@ -252,6 +252,7 @@
 }
 
 
+#if !defined(NDEBUG)
 static int check_tm(struct TM *tm)
 {
     /* Don't forget leap seconds */
@@ -283,6 +284,7 @@
 
     return 1;
 }
+#endif
 
 
 /* The exceptional centuries without leap years cause the cycle to
diff --git a/libc/dns/gethnamaddr.c b/libc/dns/gethnamaddr.c
index 1afad6d..6f30f75 100644
--- a/libc/dns/gethnamaddr.c
+++ b/libc/dns/gethnamaddr.c
@@ -539,7 +539,7 @@
 	const int one = 1;
 	struct sockaddr_un proxy_addr;
 
-	sock = socket(AF_UNIX, SOCK_STREAM, 0);
+	sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
 	if (sock < 0) {
 		return NULL;
 	}
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
index be692e3..65fd1c1 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -362,7 +362,7 @@
  */
 static int
 _test_connect(int pf, struct sockaddr *addr, size_t addrlen, unsigned mark) {
-	int s = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
+	int s = socket(pf, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
 	if (s < 0)
 		return 0;
 	if (mark != MARK_UNSET && setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
@@ -433,7 +433,7 @@
 		return EAI_NODATA;
 	}
 
-	sock = socket(AF_UNIX, SOCK_STREAM, 0);
+	sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
 	if (sock < 0) {
 		return EAI_NODATA;
 	}
@@ -884,7 +884,7 @@
 	 * filter out AFs that are not supported by the kernel
 	 * XXX errno?
 	 */
-	s = socket(pai->ai_family, SOCK_DGRAM, 0);
+	s = socket(pai->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (s < 0) {
 		if (errno != EMFILE)
 			return 0;
@@ -1792,7 +1792,7 @@
 		return 0;
 	}
 
-	sock = socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+	sock = socket(addr->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
 	if (sock == -1) {
 		if (errno == EAFNOSUPPORT) {
 			return 0;
diff --git a/libc/dns/net/nsdispatch.c b/libc/dns/net/nsdispatch.c
index 15282be..fb6d8f6 100644
--- a/libc/dns/net/nsdispatch.c
+++ b/libc/dns/net/nsdispatch.c
@@ -69,26 +69,14 @@
  */
 
 #include <sys/cdefs.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/stat.h>
 
 #include <assert.h>
-#ifdef __ELF__
-#include <dlfcn.h>
-#endif /* __ELF__ */
-#include <fcntl.h>
-#define _NS_PRIVATE
 #include <nsswitch.h>
 #include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <strings.h>
-#include <unistd.h>
 
 static nss_method
-_nsmethod(const char *source, const char *database, const char *method,
+_nsmethod(const char *source, const char *database __unused, const char *method __unused,
     const ns_dtab disp_tab[], void **cb_data)
 {
 	int	curdisp;
diff --git a/libc/dns/resolv/res_init.c b/libc/dns/resolv/res_init.c
index 9f3a9da..158466e 100644
--- a/libc/dns/resolv/res_init.c
+++ b/libc/dns/resolv/res_init.c
@@ -611,7 +611,7 @@
 static int
 real_randomid(u_int *random_value) {
 	/* open the nonblocking random device, returning -1 on failure */
-	int random_device = open("/dev/urandom", O_RDONLY);
+	int random_device = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
 	if (random_device < 0) {
 		return -1;
 	}
diff --git a/libc/dns/resolv/res_send.c b/libc/dns/resolv/res_send.c
index 9b36f55..b6a990a 100644
--- a/libc/dns/resolv/res_send.c
+++ b/libc/dns/resolv/res_send.c
@@ -779,7 +779,7 @@
 		if (statp->_vcsock >= 0)
 			res_nclose(statp);
 
-		statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
+		statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
 		if (statp->_vcsock > highestFD) {
 			res_nclose(statp);
 			errno = ENOTSOCK;
@@ -1062,7 +1062,7 @@
 	nsap = get_nsaddr(statp, (size_t)ns);
 	nsaplen = get_salen(nsap);
 	if (EXT(statp).nssocks[ns] == -1) {
-		EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
+		EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 		if (EXT(statp).nssocks[ns] > highestFD) {
 			res_nclose(statp);
 			errno = ENOTSOCK;
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index cd68154..4450bb6 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -33,6 +33,7 @@
 #include <sys/types.h>
 #include <linux/fadvise.h>
 #include <linux/fcntl.h>
+#include <linux/uio.h>
 #include <unistd.h>  /* this is not required, but makes client code much happier */
 
 __BEGIN_DECLS
@@ -51,9 +52,12 @@
 #define F_SETLKW64 F_SETLKW
 #endif
 
-#ifndef O_ASYNC
-#define O_ASYNC  FASYNC
-#endif
+#define O_ASYNC FASYNC
+
+#define SPLICE_F_MOVE 1
+#define SPLICE_F_NONBLOCK 2
+#define SPLICE_F_MORE 4
+#define SPLICE_F_GIFT 8
 
 #define SYNC_FILE_RANGE_WAIT_BEFORE 1
 #define SYNC_FILE_RANGE_WRITE 2
@@ -70,7 +74,10 @@
 extern int open64(const char*, int, ...);
 extern int posix_fallocate64(int, off64_t, off64_t);
 extern int posix_fallocate(int, off_t, off_t);
+extern ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int);
+extern ssize_t tee(int, int, size_t, unsigned int);
 extern int unlinkat(int, const char*, int);
+extern ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int);
 
 #if defined(__BIONIC_FORTIFY)
 
diff --git a/libc/dns/include/nsswitch.h b/libc/include/nsswitch.h
similarity index 91%
rename from libc/dns/include/nsswitch.h
rename to libc/include/nsswitch.h
index e03844b..af88433 100644
--- a/libc/dns/include/nsswitch.h
+++ b/libc/include/nsswitch.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: nsswitch.h,v 1.18 2005/11/29 03:12:58 christos Exp $	*/
+/*	$NetBSD: nsswitch.h,v 1.21 2011/07/17 20:54:34 joerg Exp $	*/
 
 /*-
  * Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc.
@@ -15,13 +15,6 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *        This product includes software developed by the NetBSD
- *        Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
@@ -137,6 +130,7 @@
 #else
 #   define NS_NIS_CB(F,C)
 #endif
+#define	NS_NULL_CB		{ .src = NULL },
 
 /*
  * ns_src - `nsswitch source'
@@ -149,7 +143,6 @@
 } ns_src;
 
 
-#if 0
 /*
  * Default sourcelists (if nsswitch.conf is missing, corrupt,
  * or the requested database doesn't have an entry)
@@ -161,7 +154,7 @@
 extern const ns_src __nsdefaultfiles_forceall[];
 extern const ns_src __nsdefaultnis[];
 extern const ns_src __nsdefaultnis_forceall[];
-#endif
+
 
 /*
  * ns_mtab - `nsswitch method table'
@@ -222,7 +215,7 @@
 
 __BEGIN_DECLS
 int	nsdispatch(void *, const ns_dtab [], const char *,
-			const char *, const ns_src [], ...);
+			const char *, const ns_src [], ...) __LIBC_ABI_PUBLIC__;
 
 #ifdef _NS_PRIVATE
 int		 _nsdbtaddsrc(ns_dbt *, const ns_src *);
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 0063b24..f1849c5 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -34,6 +34,7 @@
 #include <limits.h>		/* For LONG_BIT */
 #include <string.h>		/* For memset() */
 #include <sys/types.h>
+#include <asm/sigcontext.h>
 
 #if defined(__LP64__) || defined(__mips__)
 /* For 64-bit (and mips), the kernel's struct sigaction doesn't match the POSIX one,
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index 266aa5e..62b7a67 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -100,9 +100,10 @@
 extern double erand48(unsigned short xsubi[3]);
 extern double drand48(void);
 extern void srand48(long);
-extern unsigned int arc4random(void);
-extern void arc4random_stir(void);
-extern void arc4random_addrandom(unsigned char *, int);
+
+unsigned int arc4random(void);
+unsigned int arc4random_uniform(unsigned int);
+void arc4random_buf(void*, size_t);
 
 #define RAND_MAX 0x7fffffff
 
diff --git a/libc/include/strings.h b/libc/include/strings.h
index c4d5f6c..ae261cf 100644
--- a/libc/include/strings.h
+++ b/libc/include/strings.h
@@ -43,8 +43,16 @@
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
-#define bcopy(b1, b2, len) (void)(memmove((b2), (b1), (len)))
-#define bzero(b, len) (void)(memset((b), '\0', (len)))
+#if defined(__BIONIC_FORTIFY)
+#define bcopy(b1, b2, len) \
+  (void)(__builtin___memmove_chk((b2), (b1), (len), __bos0(b2)))
+#define bzero(b, len) \
+  (void)(__builtin___memset_chk((b), '\0', (len), __bos0(b)))
+#else
+#define bcopy(b1, b2, len) (void)(__builtin_memmove((b2), (b1), (len)))
+#define bzero(b, len) (void)(__builtin_memset((b), '\0', (len)))
+#endif
+
 
 int	 ffs(int);
 int	 strcasecmp(const char *, const char *);
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index 7edaac9..ae2f238 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -107,7 +107,7 @@
   int cmsg_type;
 };
 
-#define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr((mhdr), (cmsg))
+#define CMSG_NXTHDR(mhdr, cmsg) __cmsg_nxthdr((mhdr), (cmsg))
 #define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
 #define CMSG_DATA(cmsg) ((void*)((char*)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
 #define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
@@ -117,7 +117,7 @@
    ? (struct cmsghdr*) (msg)->msg_control : (struct cmsghdr*) NULL)
 #define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) &&   (cmsg)->cmsg_len <= (unsigned long)   ((mhdr)->msg_controllen -   ((char*)(cmsg) - (char*)(mhdr)->msg_control)))
 
-struct cmsghdr* cmsg_nxthdr(struct msghdr*, struct cmsghdr*);
+struct cmsghdr* __cmsg_nxthdr(struct msghdr*, struct cmsghdr*);
 
 #define SCM_RIGHTS 0x01
 #define SCM_CREDENTIALS 0x02
diff --git a/libc/include/sys/types.h b/libc/include/sys/types.h
index 9a76ad2..a5fa692 100644
--- a/libc/include/sys/types.h
+++ b/libc/include/sys/types.h
@@ -91,12 +91,17 @@
 typedef __time_t time_t;
 
 /* This historical accident means that we had a 32-bit off_t on 32-bit architectures. */
-#ifndef _OFF_T_DEFINED_
-#define _OFF_T_DEFINED_
+#if !defined(__LP64__)
 typedef __kernel_off_t off_t;
-#endif
 typedef __kernel_loff_t loff_t;
 typedef loff_t off64_t;
+#else
+/* We could re-use the LP32 definitions, but that would mean that although off_t and loff_t/off64_t
+ * would be the same size, they wouldn't actually be the same type, which can lead to warnings. */
+typedef __kernel_off_t off_t;
+typedef off_t loff_t;
+typedef loff_t off64_t;
+#endif
 
 /* while POSIX wants these in <sys/types.h>, we
  * declare then in <pthread.h> instead */
diff --git a/libc/private/thread_private.h b/libc/private/thread_private.h
index f731181..724808a 100644
--- a/libc/private/thread_private.h
+++ b/libc/private/thread_private.h
@@ -7,6 +7,8 @@
 
 #include <pthread.h>
 
+__BEGIN_DECLS
+
 /*
  * This file defines the thread library interface to libc.  Thread
  * libraries must implement the functions described here for proper
@@ -31,10 +33,18 @@
 #define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \
 	pthread_mutex_unlock( &__THREAD_NAME(name)._private_lock )
 
-void	_thread_atexit_lock(void);
-void	_thread_atexit_unlock(void);
+__LIBC_HIDDEN__ void	_thread_atexit_lock(void);
+__LIBC_HIDDEN__ void	_thread_atexit_unlock(void);
 
 #define _ATEXIT_LOCK() _thread_atexit_lock()
 #define _ATEXIT_UNLOCK() _thread_atexit_unlock()
 
+__LIBC_HIDDEN__ void    _thread_arc4_lock(void);
+__LIBC_HIDDEN__ void    _thread_arc4_unlock(void);
+
+#define  _ARC4_LOCK() _thread_arc4_lock()
+#define  _ARC4_UNLOCK() _thread_arc4_unlock()
+
+__END_DECLS
+
 #endif /* _THREAD_PRIVATE_H_ */
diff --git a/libc/upstream-netbsd/lib/libc/include/resolv_mt.h b/libc/upstream-netbsd/lib/libc/include/resolv_mt.h
new file mode 100644
index 0000000..73a8dcc
--- /dev/null
+++ b/libc/upstream-netbsd/lib/libc/include/resolv_mt.h
@@ -0,0 +1,49 @@
+/*	$NetBSD: resolv_mt.h,v 1.1.1.3 2009/04/12 16:35:44 christos Exp $	*/
+
+#ifndef _RESOLV_MT_H
+#define _RESOLV_MT_H
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+/* Access functions for the libresolv private interface */
+
+int	__res_enable_mt(void);
+int	__res_disable_mt(void);
+
+/* Per-thread context */
+
+typedef struct {
+int	no_hosts_fallback_private;
+int	retry_save;
+int	retry_private;
+char	inet_nsap_ntoa_tmpbuf[255*3];
+char	sym_ntos_unname[20];
+char	sym_ntop_unname[20];
+char	p_option_nbuf[40];
+char	p_time_nbuf[40];
+char	precsize_ntoa_retbuf[sizeof "90000000.00"];
+char	loc_ntoa_tmpbuf[sizeof
+"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
+char	p_secstodate_output[15];
+} mtctxres_t;
+
+/* Thread-specific data (TSD) */
+
+mtctxres_t	*___mtctxres(void);
+#define mtctxres	(___mtctxres())
+
+/* Various static data that should be TSD */
+
+#define sym_ntos_unname		(mtctxres->sym_ntos_unname)
+#define sym_ntop_unname		(mtctxres->sym_ntop_unname)
+#define inet_nsap_ntoa_tmpbuf	(mtctxres->inet_nsap_ntoa_tmpbuf)
+#define p_option_nbuf		(mtctxres->p_option_nbuf)
+#define p_time_nbuf		(mtctxres->p_time_nbuf)
+#define precsize_ntoa_retbuf	(mtctxres->precsize_ntoa_retbuf)
+#define loc_ntoa_tmpbuf		(mtctxres->loc_ntoa_tmpbuf)
+#define p_secstodate_output	(mtctxres->p_secstodate_output)
+
+#endif /* _RESOLV_MT_H */
diff --git a/libc/dns/inet/nsap_addr.c b/libc/upstream-netbsd/lib/libc/inet/nsap_addr.c
similarity index 81%
rename from libc/dns/inet/nsap_addr.c
rename to libc/upstream-netbsd/lib/libc/inet/nsap_addr.c
index 4deabac..8633205 100644
--- a/libc/dns/inet/nsap_addr.c
+++ b/libc/upstream-netbsd/lib/libc/inet/nsap_addr.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: nsap_addr.c,v 1.2 2004/05/20 23:12:33 christos Exp $	*/
+/*	$NetBSD: nsap_addr.c,v 1.6 2009/04/12 17:07:17 christos Exp $	*/
 
 /*
  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
@@ -20,12 +20,15 @@
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
 #if 0
-static const char rcsid[] = "Id: nsap_addr.c,v 1.2.206.1 2004/03/09 08:33:33 marka Exp";
+static const char rcsid[] = "Id: nsap_addr.c,v 1.5 2005/07/28 06:51:48 marka Exp";
 #else
-__RCSID("$NetBSD: nsap_addr.c,v 1.2 2004/05/20 23:12:33 christos Exp $");
+__RCSID("$NetBSD: nsap_addr.c,v 1.6 2009/04/12 17:07:17 christos Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
+#include "port_before.h"
+
+#include "namespace.h"
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/socket.h>
@@ -36,10 +39,14 @@
 
 #include <assert.h>
 #include <ctype.h>
-#ifdef ANDROID_CHANGES
-#include "resolv_private.h"
-#else
 #include <resolv.h>
+#include <resolv_mt.h>
+
+#include "port_after.h"
+
+#ifdef __weak_alias
+__weak_alias(inet_nsap_addr,_inet_nsap_addr)
+__weak_alias(inet_nsap_ntoa,_inet_nsap_ntoa)
 #endif
 
 static char
@@ -52,8 +59,8 @@
 	u_char c, nib;
 	u_int len = 0;
 
-	assert(ascii != NULL);
-	assert(binary != NULL);
+	_DIAGASSERT(ascii != NULL);
+	_DIAGASSERT(binary != NULL);
 
 	if (ascii[0] != '0' || (ascii[1] != 'x' && ascii[1] != 'X'))
 		return (0);
@@ -90,10 +97,10 @@
 inet_nsap_ntoa(int binlen, const u_char *binary, char *ascii) {
 	int nib;
 	int i;
-	static char tmpbuf[2+255*3];
+	char *tmpbuf = inet_nsap_ntoa_tmpbuf;
 	char *start;
 
-	assert(binary != NULL);
+	_DIAGASSERT(binary != NULL);
 
 	if (ascii)
 		start = ascii;
@@ -119,3 +126,5 @@
 	*ascii = '\0';
 	return (start);
 }
+
+/*! \file */
diff --git a/libc/upstream-netbsd/lib/libc/resolv/mtctxres.c b/libc/upstream-netbsd/lib/libc/resolv/mtctxres.c
new file mode 100644
index 0000000..6e3281a
--- /dev/null
+++ b/libc/upstream-netbsd/lib/libc/resolv/mtctxres.c
@@ -0,0 +1,130 @@
+/*	$NetBSD: mtctxres.c,v 1.4 2007/03/30 20:40:52 ghen Exp $	*/
+
+#include <port_before.h>
+#ifdef DO_PTHREADS
+#include <pthread.h>
+#endif
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <resolv_mt.h>
+#include <port_after.h>
+
+#ifdef DO_PTHREADS
+static pthread_key_t	key;
+static int		mt_key_initialized = 0;
+
+static int		__res_init_ctx(void);
+static void		__res_destroy_ctx(void *);
+
+#if defined(sun) && !defined(__GNUC__)
+#pragma init	(_mtctxres_init)
+#endif
+#endif
+
+static mtctxres_t	sharedctx;
+
+#ifdef DO_PTHREADS
+/*
+ * Initialize the TSD key. By doing this at library load time, we're
+ * implicitly running without interference from other threads, so there's
+ * no need for locking.
+ */
+static void
+_mtctxres_init(void) {
+	int pthread_keycreate_ret;
+
+	pthread_keycreate_ret = pthread_key_create(&key, __res_destroy_ctx);
+	if (pthread_keycreate_ret == 0)
+		mt_key_initialized = 1;
+}
+#endif
+
+/*
+ * To support binaries that used the private MT-safe interface in
+ * Solaris 8, we still need to provide the __res_enable_mt()
+ * and __res_disable_mt() entry points. They're do-nothing routines.
+ */
+int
+__res_enable_mt(void) {
+	return (-1);
+}
+
+int
+__res_disable_mt(void) {
+	return (0);
+}
+
+#ifdef DO_PTHREADS
+static int
+__res_init_ctx(void) {
+
+	mtctxres_t	*mt;
+	int		ret;
+
+
+	if (pthread_getspecific(key) != 0) {
+		/* Already exists */
+		return (0);
+	}
+
+	if ((mt = malloc(sizeof (mtctxres_t))) == 0) {
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	memset(mt, 0, sizeof (mtctxres_t));
+
+	if ((ret = pthread_setspecific(key, mt)) != 0) {
+		free(mt);
+		errno = ret;
+		return (-1);
+	}
+
+	return (0);
+}
+
+static void
+__res_destroy_ctx(void *value) {
+
+	mtctxres_t	*mt = (mtctxres_t *)value;
+
+	if (mt != 0)
+		free(mt);
+}
+#endif
+
+mtctxres_t *
+___mtctxres(void) {
+#ifdef DO_PTHREADS
+	mtctxres_t	*mt;
+
+	/*
+	 * This if clause should only be executed if we are linking
+	 * statically.  When linked dynamically _mtctxres_init() should
+	 * be called at binding time due the #pragma above.
+	 */
+	if (!mt_key_initialized) {
+		static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER;
+                if (pthread_mutex_lock(&keylock) == 0) {
+			_mtctxres_init();
+			(void) pthread_mutex_unlock(&keylock);
+		}
+	}
+
+	/*
+	 * If we have already been called in this thread return the existing
+	 * context.  Otherwise recreat a new context and return it.  If
+	 * that fails return a global context.
+	 */
+	if (mt_key_initialized) {
+		if (((mt = pthread_getspecific(key)) != 0) ||
+		    (__res_init_ctx() == 0 &&
+		     (mt = pthread_getspecific(key)) != 0)) {
+			return (mt);
+		}
+	}
+#endif
+	return (&sharedctx);
+}
diff --git a/libc/upstream-openbsd/lib/libc/crypt/chacha_private.h b/libc/upstream-openbsd/lib/libc/crypt/chacha_private.h
new file mode 100644
index 0000000..7c3680f
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/crypt/chacha_private.h
@@ -0,0 +1,222 @@
+/*
+chacha-merged.c version 20080118
+D. J. Bernstein
+Public domain.
+*/
+
+/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */
+
+typedef unsigned char u8;
+typedef unsigned int u32;
+
+typedef struct
+{
+  u32 input[16]; /* could be compressed */
+} chacha_ctx;
+
+#define U8C(v) (v##U)
+#define U32C(v) (v##U)
+
+#define U8V(v) ((u8)(v) & U8C(0xFF))
+#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
+
+#define ROTL32(v, n) \
+  (U32V((v) << (n)) | ((v) >> (32 - (n))))
+
+#define U8TO32_LITTLE(p) \
+  (((u32)((p)[0])      ) | \
+   ((u32)((p)[1]) <<  8) | \
+   ((u32)((p)[2]) << 16) | \
+   ((u32)((p)[3]) << 24))
+
+#define U32TO8_LITTLE(p, v) \
+  do { \
+    (p)[0] = U8V((v)      ); \
+    (p)[1] = U8V((v) >>  8); \
+    (p)[2] = U8V((v) >> 16); \
+    (p)[3] = U8V((v) >> 24); \
+  } while (0)
+
+#define ROTATE(v,c) (ROTL32(v,c))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) (U32V((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+
+#define QUARTERROUND(a,b,c,d) \
+  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
+  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
+  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
+  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
+
+static const char sigma[16] = "expand 32-byte k";
+static const char tau[16] = "expand 16-byte k";
+
+static void
+chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
+{
+  const char *constants;
+
+  x->input[4] = U8TO32_LITTLE(k + 0);
+  x->input[5] = U8TO32_LITTLE(k + 4);
+  x->input[6] = U8TO32_LITTLE(k + 8);
+  x->input[7] = U8TO32_LITTLE(k + 12);
+  if (kbits == 256) { /* recommended */
+    k += 16;
+    constants = sigma;
+  } else { /* kbits == 128 */
+    constants = tau;
+  }
+  x->input[8] = U8TO32_LITTLE(k + 0);
+  x->input[9] = U8TO32_LITTLE(k + 4);
+  x->input[10] = U8TO32_LITTLE(k + 8);
+  x->input[11] = U8TO32_LITTLE(k + 12);
+  x->input[0] = U8TO32_LITTLE(constants + 0);
+  x->input[1] = U8TO32_LITTLE(constants + 4);
+  x->input[2] = U8TO32_LITTLE(constants + 8);
+  x->input[3] = U8TO32_LITTLE(constants + 12);
+}
+
+static void
+chacha_ivsetup(chacha_ctx *x,const u8 *iv)
+{
+  x->input[12] = 0;
+  x->input[13] = 0;
+  x->input[14] = U8TO32_LITTLE(iv + 0);
+  x->input[15] = U8TO32_LITTLE(iv + 4);
+}
+
+static void
+chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
+{
+  u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+  u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+  u8 *ctarget = NULL;
+  u8 tmp[64];
+  u_int i;
+
+  if (!bytes) return;
+
+  j0 = x->input[0];
+  j1 = x->input[1];
+  j2 = x->input[2];
+  j3 = x->input[3];
+  j4 = x->input[4];
+  j5 = x->input[5];
+  j6 = x->input[6];
+  j7 = x->input[7];
+  j8 = x->input[8];
+  j9 = x->input[9];
+  j10 = x->input[10];
+  j11 = x->input[11];
+  j12 = x->input[12];
+  j13 = x->input[13];
+  j14 = x->input[14];
+  j15 = x->input[15];
+
+  for (;;) {
+    if (bytes < 64) {
+      for (i = 0;i < bytes;++i) tmp[i] = m[i];
+      m = tmp;
+      ctarget = c;
+      c = tmp;
+    }
+    x0 = j0;
+    x1 = j1;
+    x2 = j2;
+    x3 = j3;
+    x4 = j4;
+    x5 = j5;
+    x6 = j6;
+    x7 = j7;
+    x8 = j8;
+    x9 = j9;
+    x10 = j10;
+    x11 = j11;
+    x12 = j12;
+    x13 = j13;
+    x14 = j14;
+    x15 = j15;
+    for (i = 20;i > 0;i -= 2) {
+      QUARTERROUND( x0, x4, x8,x12)
+      QUARTERROUND( x1, x5, x9,x13)
+      QUARTERROUND( x2, x6,x10,x14)
+      QUARTERROUND( x3, x7,x11,x15)
+      QUARTERROUND( x0, x5,x10,x15)
+      QUARTERROUND( x1, x6,x11,x12)
+      QUARTERROUND( x2, x7, x8,x13)
+      QUARTERROUND( x3, x4, x9,x14)
+    }
+    x0 = PLUS(x0,j0);
+    x1 = PLUS(x1,j1);
+    x2 = PLUS(x2,j2);
+    x3 = PLUS(x3,j3);
+    x4 = PLUS(x4,j4);
+    x5 = PLUS(x5,j5);
+    x6 = PLUS(x6,j6);
+    x7 = PLUS(x7,j7);
+    x8 = PLUS(x8,j8);
+    x9 = PLUS(x9,j9);
+    x10 = PLUS(x10,j10);
+    x11 = PLUS(x11,j11);
+    x12 = PLUS(x12,j12);
+    x13 = PLUS(x13,j13);
+    x14 = PLUS(x14,j14);
+    x15 = PLUS(x15,j15);
+
+#ifndef KEYSTREAM_ONLY
+    x0 = XOR(x0,U8TO32_LITTLE(m + 0));
+    x1 = XOR(x1,U8TO32_LITTLE(m + 4));
+    x2 = XOR(x2,U8TO32_LITTLE(m + 8));
+    x3 = XOR(x3,U8TO32_LITTLE(m + 12));
+    x4 = XOR(x4,U8TO32_LITTLE(m + 16));
+    x5 = XOR(x5,U8TO32_LITTLE(m + 20));
+    x6 = XOR(x6,U8TO32_LITTLE(m + 24));
+    x7 = XOR(x7,U8TO32_LITTLE(m + 28));
+    x8 = XOR(x8,U8TO32_LITTLE(m + 32));
+    x9 = XOR(x9,U8TO32_LITTLE(m + 36));
+    x10 = XOR(x10,U8TO32_LITTLE(m + 40));
+    x11 = XOR(x11,U8TO32_LITTLE(m + 44));
+    x12 = XOR(x12,U8TO32_LITTLE(m + 48));
+    x13 = XOR(x13,U8TO32_LITTLE(m + 52));
+    x14 = XOR(x14,U8TO32_LITTLE(m + 56));
+    x15 = XOR(x15,U8TO32_LITTLE(m + 60));
+#endif
+
+    j12 = PLUSONE(j12);
+    if (!j12) {
+      j13 = PLUSONE(j13);
+      /* stopping at 2^70 bytes per nonce is user's responsibility */
+    }
+
+    U32TO8_LITTLE(c + 0,x0);
+    U32TO8_LITTLE(c + 4,x1);
+    U32TO8_LITTLE(c + 8,x2);
+    U32TO8_LITTLE(c + 12,x3);
+    U32TO8_LITTLE(c + 16,x4);
+    U32TO8_LITTLE(c + 20,x5);
+    U32TO8_LITTLE(c + 24,x6);
+    U32TO8_LITTLE(c + 28,x7);
+    U32TO8_LITTLE(c + 32,x8);
+    U32TO8_LITTLE(c + 36,x9);
+    U32TO8_LITTLE(c + 40,x10);
+    U32TO8_LITTLE(c + 44,x11);
+    U32TO8_LITTLE(c + 48,x12);
+    U32TO8_LITTLE(c + 52,x13);
+    U32TO8_LITTLE(c + 56,x14);
+    U32TO8_LITTLE(c + 60,x15);
+
+    if (bytes <= 64) {
+      if (bytes < 64) {
+        for (i = 0;i < bytes;++i) ctarget[i] = c[i];
+      }
+      x->input[12] = j12;
+      x->input[13] = j13;
+      return;
+    }
+    bytes -= 64;
+    c += 64;
+#ifndef KEYSTREAM_ONLY
+    m += 64;
+#endif
+  }
+}
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 0b60ef5..efb829e 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -100,30 +100,23 @@
 
   soinfo* found = NULL;
   ElfW(Sym)* sym = NULL;
-  if (handle == RTLD_DEFAULT || handle == (void*)0xffffffffL) {
-    sym = dlsym_linear_lookup(symbol, &found, NULL);
-  } else if (handle == RTLD_NEXT || handle == (void*)0xfffffffeL) {
-    void* caller_addr = __builtin_return_address(0);
-    soinfo* si = find_containing_library(caller_addr);
+  void* caller_addr = __builtin_return_address(0);
+  soinfo* caller_si = find_containing_library(caller_addr);
 
+  if (handle == RTLD_DEFAULT) {
+    sym = dlsym_linear_lookup(symbol, &found, NULL, caller_si);
+  } else if (handle == RTLD_NEXT) {
     sym = NULL;
-    if (si && si->next) {
-      sym = dlsym_linear_lookup(symbol, &found, si->next);
+    if (caller_si && caller_si->next) {
+      sym = dlsym_linear_lookup(symbol, &found, caller_si->next, caller_si);
     }
   } else {
     found = reinterpret_cast<soinfo*>(handle);
-    sym = dlsym_handle_lookup(found, symbol);
+    sym = dlsym_handle_lookup(found, symbol, caller_si);
   }
 
-  if (sym != NULL) {
-    unsigned bind = ELF_ST_BIND(sym->st_info);
-
-    if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
-      return reinterpret_cast<void*>(sym->st_value + found->load_bias);
-    }
-
-    __bionic_format_dlerror("symbol found but not global", symbol);
-    return NULL;
+  if (sym != NULL && sym->st_shndx != 0) {
+    return reinterpret_cast<void*>(sym->st_value + found->load_bias);
   } else {
     __bionic_format_dlerror("undefined symbol", symbol);
     return NULL;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index e202aaf..bf923c1 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -125,6 +125,11 @@
     kRelocMax
 };
 
+enum class SymbolLookupScope {
+  kAllowLocal,
+  kExcludeLocal,
+};
+
 #if STATS
 struct linker_stats_t {
     int count[kRelocMax];
@@ -163,10 +168,7 @@
 #define DISALLOW_ALLOCATION(return_type, name, ...) \
     return_type name __VA_ARGS__ \
     { \
-        const char* msg = "ERROR: " #name " called from the dynamic linker!\n"; \
-        __libc_format_log(ANDROID_LOG_FATAL, "linker", "%s", msg); \
-        write(2, msg, strlen(msg)); \
-        abort(); \
+        __libc_fatal("ERROR: " #name " called from the dynamic linker!\n"); \
     }
 DISALLOW_ALLOCATION(void*, malloc, (size_t u __unused));
 DISALLOW_ALLOCATION(void, free, (void* u __unused));
@@ -431,7 +433,7 @@
     return rv;
 }
 
-static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
+static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name, const SymbolLookupScope& lookup_scope) {
   ElfW(Sym)* symtab = si->symtab;
   const char* strtab = si->strtab;
 
@@ -442,18 +444,28 @@
     ElfW(Sym)* s = symtab + n;
     if (strcmp(strtab + s->st_name, name)) continue;
 
-    /* only concern ourselves with global and weak symbol definitions */
     switch (ELF_ST_BIND(s->st_info)) {
       case STB_GLOBAL:
       case STB_WEAK:
         if (s->st_shndx == SHN_UNDEF) {
-        continue;
-      }
+          continue;
+        }
 
-      TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
+        TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
                  name, si->name, reinterpret_cast<void*>(s->st_value),
                  static_cast<size_t>(s->st_size));
-      return s;
+        return s;
+      case STB_LOCAL:
+        if (lookup_scope != SymbolLookupScope::kAllowLocal) {
+          continue;
+        }
+        TRACE_TYPE(LOOKUP, "FOUND LOCAL %s in %s (%p) %zd",
+                name, si->name, reinterpret_cast<void*>(s->st_value),
+                static_cast<size_t>(s->st_size));
+        return s;
+      default:
+        __libc_fatal("ERROR: Unexpected ST_BIND value: %d for '%s' in '%s'",
+            ELF_ST_BIND(s->st_info), name, si->name);
     }
   }
 
@@ -484,7 +496,7 @@
          */
 
         if (si == somain) {
-            s = soinfo_elf_lookup(si, elf_hash, name);
+            s = soinfo_elf_lookup(si, elf_hash, name, SymbolLookupScope::kAllowLocal);
             if (s != NULL) {
                 *lsi = si;
                 goto done;
@@ -501,7 +513,7 @@
             if (!si->has_DT_SYMBOLIC) {
                 DEBUG("%s: looking up %s in executable %s",
                       si->name, name, somain->name);
-                s = soinfo_elf_lookup(somain, elf_hash, name);
+                s = soinfo_elf_lookup(somain, elf_hash, name, SymbolLookupScope::kExcludeLocal);
                 if (s != NULL) {
                     *lsi = somain;
                     goto done;
@@ -518,7 +530,7 @@
              * and some the first non-weak definition.   This is system dependent.
              * Here we return the first definition found for simplicity.  */
 
-            s = soinfo_elf_lookup(si, elf_hash, name);
+            s = soinfo_elf_lookup(si, elf_hash, name, SymbolLookupScope::kAllowLocal);
             if (s != NULL) {
                 *lsi = si;
                 goto done;
@@ -532,7 +544,7 @@
             if (si->has_DT_SYMBOLIC) {
                 DEBUG("%s: looking up %s in executable %s after local scope",
                       si->name, name, somain->name);
-                s = soinfo_elf_lookup(somain, elf_hash, name);
+                s = soinfo_elf_lookup(somain, elf_hash, name, SymbolLookupScope::kExcludeLocal);
                 if (s != NULL) {
                     *lsi = somain;
                     goto done;
@@ -543,7 +555,7 @@
 
     /* Next, look for it in the preloads list */
     for (int i = 0; g_ld_preloads[i] != NULL; i++) {
-        s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name);
+        s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name, SymbolLookupScope::kExcludeLocal);
         if (s != NULL) {
             *lsi = g_ld_preloads[i];
             goto done;
@@ -553,7 +565,7 @@
     for (int i = 0; needed[i] != NULL; i++) {
         DEBUG("%s: looking up %s in %s",
               si->name, name, needed[i]->name);
-        s = soinfo_elf_lookup(needed[i], elf_hash, name);
+        s = soinfo_elf_lookup(needed[i], elf_hash, name, SymbolLookupScope::kExcludeLocal);
         if (s != NULL) {
             *lsi = needed[i];
             goto done;
@@ -582,8 +594,9 @@
    Binary Interface) where in Chapter 5 it discuss resolving "Shared
    Object Dependencies" in breadth first search order.
  */
-ElfW(Sym)* dlsym_handle_lookup(soinfo* si, const char* name) {
-    return soinfo_elf_lookup(si, elfhash(name), name);
+ElfW(Sym)* dlsym_handle_lookup(soinfo* si, const char* name, soinfo* caller) {
+    return soinfo_elf_lookup(si, elfhash(name), name,
+        caller == si ? SymbolLookupScope::kAllowLocal : SymbolLookupScope::kExcludeLocal);
 }
 
 /* This is used by dlsym(3) to performs a global symbol lookup. If the
@@ -591,7 +604,7 @@
    beginning of the global solist. Otherwise the search starts at the
    specified soinfo (for RTLD_NEXT).
  */
-ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
+ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start, soinfo* caller) {
   unsigned elf_hash = elfhash(name);
 
   if (start == NULL) {
@@ -600,7 +613,8 @@
 
   ElfW(Sym)* s = NULL;
   for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) {
-    s = soinfo_elf_lookup(si, elf_hash, name);
+    s = soinfo_elf_lookup(si, elf_hash, name,
+        caller == si ? SymbolLookupScope::kAllowLocal : SymbolLookupScope::kExcludeLocal);
     if (s != NULL) {
       *found = si;
       break;
@@ -669,8 +683,7 @@
     }
     // ...but nvidia binary blobs (at least) rely on this behavior, so fall through for now.
 #if defined(__LP64__)
-    // TODO: uncomment this after bug b/7465467 is fixed.
-    // return -1;
+    return -1;
 #endif
   }
 
@@ -1930,10 +1943,8 @@
     if (si->has_text_relocations) {
         // Make segments writable to allow text relocations to work properly. We will later call
         // phdr_table_protect_segments() after all of them are applied and all constructors are run.
-#if !defined(__i386__) // The platform itself has too many text relocations on x86.
         DL_WARN("%s has text relocations. This is wasting memory and prevents "
                 "security hardening. Please fix.", si->name);
-#endif
         if (phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias) < 0) {
             DL_ERR("can't unprotect loadable segments for \"%s\": %s",
                    si->name, strerror(errno));
diff --git a/linker/linker.h b/linker/linker.h
index 0a72d92..e1112e6 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -234,11 +234,11 @@
 soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
 void do_dlclose(soinfo* si);
 
-ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start);
+ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start, soinfo* caller_si);
 soinfo* find_containing_library(const void* addr);
 
 ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr);
-ElfW(Sym)* dlsym_handle_lookup(soinfo* si, const char* name);
+ElfW(Sym)* dlsym_handle_lookup(soinfo* si, const char* name, soinfo* caller_si);
 
 void debuggerd_init();
 extern "C" abort_msg_t* g_abort_message;
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 8b89183..18963cf 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -50,6 +50,20 @@
   ASSERT_EQ(0, dlclose(self));
 }
 
+TEST(dlfcn, dlsym_local_symbol) {
+  void* handle = dlopen("libtest_local_symbol.so", RTLD_NOW);
+  ASSERT_TRUE(handle != NULL);
+  dlerror();
+  void* sym = dlsym(handle, "private_taxicab_number");
+  ASSERT_TRUE(sym == NULL);
+  ASSERT_STREQ("undefined symbol: private_taxicab_number", dlerror());
+
+  uint32_t (*f)(void);
+  f = reinterpret_cast<uint32_t (*)(void)>(dlsym(handle, "dlsym_local_symbol_get_taxicab_number_using_dlsym"));
+  ASSERT_TRUE(f != NULL);
+  ASSERT_EQ(1729, f());
+}
+
 TEST(dlfcn, dlopen_noload) {
   void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
   ASSERT_TRUE(handle == NULL);
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index fb6b07e..5f20295 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -132,3 +132,87 @@
 
   close(fd);
 }
+
+TEST(fcntl, splice) {
+  int pipe_fds[2];
+  ASSERT_EQ(0, pipe(pipe_fds));
+
+  int in = open("/proc/cpuinfo", O_RDONLY);
+  ASSERT_NE(in, -1);
+
+  TemporaryFile tf;
+
+  ssize_t bytes_read = splice(in, 0, pipe_fds[1], NULL, 8*1024, SPLICE_F_MORE | SPLICE_F_MOVE);
+  ASSERT_NE(bytes_read, -1);
+
+  ssize_t bytes_written = splice(pipe_fds[0], NULL, tf.fd, 0, bytes_read, SPLICE_F_MORE | SPLICE_F_MOVE);
+  ASSERT_EQ(bytes_read, bytes_written);
+
+  close(pipe_fds[0]);
+  close(pipe_fds[1]);
+  close(in);
+}
+
+TEST(fcntl, vmsplice) {
+  int pipe_fds[2];
+  ASSERT_EQ(0, pipe(pipe_fds));
+
+  iovec v[2];
+  v[0].iov_base = const_cast<char*>("hello ");
+  v[0].iov_len = 6;
+  v[1].iov_base = const_cast<char*>("world\n");
+  v[1].iov_len = 6;
+  ssize_t bytes_written = vmsplice(pipe_fds[1], v, sizeof(v)/sizeof(iovec), 0);
+  ASSERT_EQ(v[0].iov_len + v[1].iov_len, static_cast<size_t>(bytes_written));
+  close(pipe_fds[1]);
+
+  char buf[BUFSIZ];
+  FILE* fp = fdopen(pipe_fds[0], "r");
+  ASSERT_TRUE(fp != NULL);
+  ASSERT_TRUE(fgets(buf, sizeof(buf), fp) != NULL);
+  fclose(fp);
+  ASSERT_STREQ("hello world\n", buf);
+}
+
+TEST(fcntl, tee) {
+  char expected[256];
+  FILE* expected_fp = fopen("/proc/version", "r");
+  ASSERT_TRUE(expected_fp != NULL);
+  ASSERT_TRUE(fgets(expected, sizeof(expected), expected_fp) != NULL);
+  fclose(expected_fp);
+
+  int pipe1[2];
+  ASSERT_EQ(0, pipe(pipe1));
+
+  int pipe2[2];
+  ASSERT_EQ(0, pipe(pipe2));
+
+  int in = open("/proc/version", O_RDONLY);
+  ASSERT_NE(in, -1);
+
+  // Write /proc/version into pipe1.
+  ssize_t bytes_read = splice(in, 0, pipe1[1], NULL, 8*1024, SPLICE_F_MORE | SPLICE_F_MOVE);
+  ASSERT_NE(bytes_read, -1);
+  close(pipe1[1]);
+
+  // Tee /proc/version from pipe1 into pipe2.
+  ssize_t bytes_teed = tee(pipe1[0], pipe2[1], SIZE_MAX, 0);
+  ASSERT_EQ(bytes_read, bytes_teed);
+  close(pipe2[1]);
+
+  // The out fds of both pipe1 and pipe2 should now contain /proc/version.
+  char buf1[BUFSIZ];
+  FILE* fp1 = fdopen(pipe1[0], "r");
+  ASSERT_TRUE(fp1 != NULL);
+  ASSERT_TRUE(fgets(buf1, sizeof(buf1), fp1) != NULL);
+  fclose(fp1);
+
+  char buf2[BUFSIZ];
+  FILE* fp2 = fdopen(pipe2[0], "r");
+  ASSERT_TRUE(fp2 != NULL);
+  ASSERT_TRUE(fgets(buf2, sizeof(buf2), fp2) != NULL);
+  fclose(fp2);
+
+  ASSERT_STREQ(expected, buf1);
+  ASSERT_STREQ(expected, buf2);
+}
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index 67ea562..efce5b5 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -88,6 +88,20 @@
 build_target := SHARED_LIBRARY
 include $(TEST_PATH)/Android.build.mk
 
+# -----------------------------------------------------------------------------
+# Library used to test local symbol lookup
+# -----------------------------------------------------------------------------
+libtest_local_symbol_src_files := \
+    dlsym_local_symbol_private.cpp \
+    dlsym_local_symbol_public.cpp
+
+module := libtest_local_symbol
+build_target := SHARED_LIBRARY
+libtest_local_symbol_ldflags := -Wl,--version-script=$(LOCAL_PATH)/dlsym_local_symbol.map
+libtest_local_symbol_cppflags := -std=gnu++11
+libtest_local_symbol_shared_libraries_target := libdl
+build_type := target
+include $(TEST_PATH)/Android.build.mk
 
 # -----------------------------------------------------------------------------
 # Library used by atexit tests
diff --git a/tests/libs/dlsym_local_symbol.map b/tests/libs/dlsym_local_symbol.map
new file mode 100644
index 0000000..58a2299
--- /dev/null
+++ b/tests/libs/dlsym_local_symbol.map
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+LIBTEST_LOCAL_SYMBOL_1.0 {
+  global:
+    dlsym_local_symbol_get_taxicab_number;
+    dlsym_local_symbol_get_taxicab_number_using_dlsym;
+  local:
+    *;
+};
diff --git a/tests/libs/dlsym_local_symbol_private.cpp b/tests/libs/dlsym_local_symbol_private.cpp
new file mode 100644
index 0000000..2587508
--- /dev/null
+++ b/tests/libs/dlsym_local_symbol_private.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 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 <stdlib.h>
+#include <dlfcn.h>
+#include <stdio.h>
+
+// This symbol is declared local in
+// the linker version map: libdlsym_local_symbol.map.
+// It should not be visible from the outside.
+extern "C" const uint32_t __attribute__ ((visibility ("protected"))) private_taxicab_number = 1729;
diff --git a/tests/libs/dlsym_local_symbol_public.cpp b/tests/libs/dlsym_local_symbol_public.cpp
new file mode 100644
index 0000000..d9da32a
--- /dev/null
+++ b/tests/libs/dlsym_local_symbol_public.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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 <stdlib.h>
+#include <dlfcn.h>
+#include <stdio.h>
+
+extern const uint32_t private_taxicab_number;
+
+extern "C" {
+uint32_t dlsym_local_symbol_get_taxicab_number();
+uint32_t dlsym_local_symbol_get_taxicab_number_using_dlsym();
+}
+
+uint32_t dlsym_local_symbol_get_taxicab_number() {
+  return private_taxicab_number;
+}
+
+// Let's make sure that dlsym works correctly for local symbol
+uint32_t dlsym_local_symbol_get_taxicab_number_using_dlsym() {
+  dlerror();
+  uint32_t* ptr = reinterpret_cast<uint32_t*>(dlsym(RTLD_DEFAULT, "private_taxicab_number"));
+  if (ptr == nullptr) {
+    const char* dlerr = dlerror();
+    if (dlerr != nullptr) {
+      fprintf(stderr, "dlsym error: %s\n", dlerr);
+    } else {
+      fprintf(stderr, "dlsym returned NULL with no dlerror.\n");
+    }
+    return 0;
+  }
+
+  return *ptr;
+}
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 0f42d43..36da481 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -69,6 +69,19 @@
 #endif // __BIONIC__
 }
 
+TEST(pthread, pthread_key_delete) {
+  void* expected = reinterpret_cast<void*>(1234);
+  pthread_key_t key;
+  ASSERT_EQ(0, pthread_key_create(&key, NULL));
+  ASSERT_EQ(0, pthread_setspecific(key, expected));
+  ASSERT_EQ(expected, pthread_getspecific(key));
+  ASSERT_EQ(0, pthread_key_delete(key));
+  // After deletion, pthread_getspecific returns NULL.
+  ASSERT_EQ(NULL, pthread_getspecific(key));
+  // And you can't use pthread_setspecific with the deleted key.
+  ASSERT_EQ(EINVAL, pthread_setspecific(key, expected));
+}
+
 static void* IdFn(void* arg) {
   return arg;
 }
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index 2ab60d7..bc2c05b 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -359,6 +359,24 @@
   EXPECT_TRUE(strchr(buf, '\0') == (buf + strlen(s)));
 }
 
+TEST(string, strchr_multiple) {
+  char str[128];
+  memset(str, 'a', sizeof(str) - 1);
+  str[sizeof(str)-1] = '\0';
+
+  // Verify that strchr finds the first occurrence of 'a' in a string
+  // filled with 'a' characters. Iterate over the string putting
+  // non 'a' characters at the front of the string during each iteration
+  // and continue to verify that strchr can find the first occurrence
+  // properly. The idea is to cover all possible alignments of the location
+  // of the first occurrence of the 'a' character and which includes
+  // other 'a' characters close by.
+  for (size_t i = 0; i < sizeof(str) - 1; i++) {
+    EXPECT_EQ(&str[i], strchr(str, 'a'));
+    str[i] = 'b';
+  }
+}
+
 TEST(string, strchr) {
   int seek_char = random() & 255;
 
@@ -1235,3 +1253,29 @@
 TEST(string, memcmp_overread) {
   RunCmpBufferOverreadTest(DoMemcmpTest, DoMemcmpFailTest);
 }
+
+static void DoStrchrTest(uint8_t* buf, size_t len) {
+  if (len >= 1) {
+    char value = 32 + (len % 96);
+    char search_value = 33 + (len % 96);
+    memset(buf, value, len - 1);
+    buf[len-1] = '\0';
+    ASSERT_EQ(NULL, strchr(reinterpret_cast<char*>(buf), search_value));
+    ASSERT_EQ(reinterpret_cast<char*>(&buf[len-1]), strchr(reinterpret_cast<char*>(buf), '\0'));
+    if (len >= 2) {
+      buf[0] = search_value;
+      ASSERT_EQ(reinterpret_cast<char*>(&buf[0]), strchr(reinterpret_cast<char*>(buf), search_value));
+      buf[0] = value;
+      buf[len-2] = search_value;
+      ASSERT_EQ(reinterpret_cast<char*>(&buf[len-2]), strchr(reinterpret_cast<char*>(buf), search_value));
+    }
+  }
+}
+
+TEST(string, strchr_align) {
+  RunSingleBufferAlignTest(MEDIUM, DoStrchrTest);
+}
+
+TEST(string, strchr_overread) {
+  RunSingleBufferOverreadTest(DoStrchrTest);
+}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 95e63b3..58c9ad9 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -381,6 +381,14 @@
   TestFsyncFunction(fsync);
 }
 
+static void AssertGetPidCorrect() {
+  // The loop is just to make manual testing/debugging with strace easier.
+  pid_t getpid_syscall_result = syscall(__NR_getpid);
+  for (size_t i = 0; i < 128; ++i) {
+    ASSERT_EQ(getpid_syscall_result, getpid());
+  }
+}
+
 TEST(unistd, getpid_caching_and_fork) {
   pid_t parent_pid = getpid();
   ASSERT_EQ(syscall(__NR_getpid), parent_pid);
@@ -389,7 +397,7 @@
   ASSERT_NE(fork_result, -1);
   if (fork_result == 0) {
     // We're the child.
-    ASSERT_EQ(syscall(__NR_getpid), getpid());
+    AssertGetPidCorrect();
     ASSERT_EQ(parent_pid, getppid());
     _exit(123);
   } else {
@@ -403,12 +411,29 @@
   }
 }
 
-static void GetPidCachingHelperHelper() {
-  ASSERT_EQ(syscall(__NR_getpid), getpid());
+static int GetPidCachingCloneStartRoutine(void*) {
+  AssertGetPidCorrect();
+  return 123;
 }
 
-static void* GetPidCachingHelper(void*) {
-  GetPidCachingHelperHelper(); // Can't assert in a non-void function.
+TEST(unistd, getpid_caching_and_clone) {
+  pid_t parent_pid = getpid();
+  ASSERT_EQ(syscall(__NR_getpid), parent_pid);
+
+  void* child_stack[1024];
+  int clone_result = clone(GetPidCachingCloneStartRoutine, &child_stack[1024], CLONE_NEWNS | SIGCHLD, NULL);
+  ASSERT_NE(clone_result, -1);
+
+  ASSERT_EQ(parent_pid, getpid());
+
+  int status;
+  ASSERT_EQ(clone_result, waitpid(clone_result, &status, 0));
+  ASSERT_TRUE(WIFEXITED(status));
+  ASSERT_EQ(123, WEXITSTATUS(status));
+}
+
+static void* GetPidCachingPthreadStartRoutine(void*) {
+  AssertGetPidCorrect();
   return NULL;
 }
 
@@ -416,7 +441,7 @@
   pid_t parent_pid = getpid();
 
   pthread_t t;
-  ASSERT_EQ(0, pthread_create(&t, NULL, GetPidCachingHelper, NULL));
+  ASSERT_EQ(0, pthread_create(&t, NULL, GetPidCachingPthreadStartRoutine, NULL));
 
   ASSERT_EQ(parent_pid, getpid());