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());