diff options
154 files changed, 3819 insertions, 1838 deletions
diff --git a/libc/Android.mk b/libc/Android.mk index 3b6e3cbec..31807ddc3 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -38,8 +38,6 @@ endif # ========================================================= libc_common_src_files := \ bionic/bindresvport.c \ - bionic/daemon.c \ - bionic/err.c \ bionic/ether_aton.c \ bionic/ether_ntoa.c \ bionic/fts.c \ @@ -62,6 +60,7 @@ libc_common_src_files := \ bionic/system_properties_compat.c \ stdio/snprintf.c\ stdio/sprintf.c \ + stdio/stdio_ext.cpp \ # Fortify implementations of libc functions. libc_common_src_files += \ @@ -103,8 +102,6 @@ libc_bionic_src_files := \ bionic/__cmsg_nxthdr.cpp \ bionic/connect.cpp \ bionic/ctype.cpp \ - bionic/__cxa_guard.cpp \ - bionic/__cxa_pure_virtual.cpp \ bionic/dirent.cpp \ bionic/dup2.cpp \ bionic/epoll_create.cpp \ @@ -124,6 +121,7 @@ libc_bionic_src_files := \ bionic/getpgrp.cpp \ bionic/getpid.cpp \ bionic/gettid.cpp \ + bionic/__gnu_basename.cpp \ bionic/inotify_init.cpp \ bionic/lchown.cpp \ bionic/lfs64_support.cpp \ @@ -135,6 +133,7 @@ libc_bionic_src_files := \ bionic/link.cpp \ bionic/locale.cpp \ bionic/lstat.cpp \ + bionic/malloc_info.cpp \ bionic/mbrtoc16.cpp \ bionic/mbrtoc32.cpp \ bionic/mbstate.cpp \ @@ -143,7 +142,6 @@ libc_bionic_src_files := \ bionic/mknod.cpp \ bionic/mntent.cpp \ bionic/NetdClientDispatch.cpp \ - bionic/new.cpp \ bionic/open.cpp \ bionic/pause.cpp \ bionic/pipe.cpp \ @@ -231,6 +229,11 @@ libc_bionic_src_files := \ bionic/wchar.cpp \ bionic/wctype.cpp \ +libc_cxa_src_files := \ + bionic/__cxa_guard.cpp \ + bionic/__cxa_pure_virtual.cpp \ + bionic/new.cpp \ + libc_upstream_freebsd_src_files := \ upstream-freebsd/lib/libc/gen/ldexp.c \ upstream-freebsd/lib/libc/gen/sleep.c \ @@ -279,7 +282,6 @@ libc_upstream_netbsd_src_files := \ 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 \ @@ -334,6 +336,9 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/crypt/arc4random_uniform.c \ upstream-openbsd/lib/libc/gen/alarm.c \ upstream-openbsd/lib/libc/gen/ctype_.c \ + upstream-openbsd/lib/libc/gen/daemon.c \ + upstream-openbsd/lib/libc/gen/err.c \ + upstream-openbsd/lib/libc/gen/errx.c \ upstream-openbsd/lib/libc/gen/exec.c \ upstream-openbsd/lib/libc/gen/fnmatch.c \ upstream-openbsd/lib/libc/gen/ftok.c \ @@ -343,6 +348,12 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/gen/time.c \ upstream-openbsd/lib/libc/gen/tolower_.c \ upstream-openbsd/lib/libc/gen/toupper_.c \ + upstream-openbsd/lib/libc/gen/verr.c \ + upstream-openbsd/lib/libc/gen/verrx.c \ + upstream-openbsd/lib/libc/gen/vwarn.c \ + upstream-openbsd/lib/libc/gen/vwarnx.c \ + upstream-openbsd/lib/libc/gen/warn.c \ + upstream-openbsd/lib/libc/gen/warnx.c \ upstream-openbsd/lib/libc/locale/btowc.c \ upstream-openbsd/lib/libc/locale/mbrlen.c \ upstream-openbsd/lib/libc/locale/mbstowcs.c \ @@ -388,6 +399,7 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/stdio/fgetws.c \ upstream-openbsd/lib/libc/stdio/fileno.c \ upstream-openbsd/lib/libc/stdio/findfp.c \ + upstream-openbsd/lib/libc/stdio/fmemopen.c \ upstream-openbsd/lib/libc/stdio/fprintf.c \ upstream-openbsd/lib/libc/stdio/fpurge.c \ upstream-openbsd/lib/libc/stdio/fputc.c \ @@ -416,6 +428,8 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/stdio/getwchar.c \ upstream-openbsd/lib/libc/stdio/makebuf.c \ upstream-openbsd/lib/libc/stdio/mktemp.c \ + upstream-openbsd/lib/libc/stdio/open_memstream.c \ + upstream-openbsd/lib/libc/stdio/open_wmemstream.c \ upstream-openbsd/lib/libc/stdio/perror.c \ upstream-openbsd/lib/libc/stdio/printf.c \ upstream-openbsd/lib/libc/stdio/putc.c \ @@ -635,8 +649,15 @@ LOCAL_SRC_FILES := \ $(call all-c-files-under,dns) \ upstream-netbsd/lib/libc/isc/ev_streams.c \ upstream-netbsd/lib/libc/isc/ev_timers.c \ + upstream-netbsd/lib/libc/resolv/mtctxres.c \ -LOCAL_CFLAGS := \ +# We use the OpenBSD res_random. +LOCAL_CFLAGS += \ + -Dres_randomid=__res_randomid +LOCAL_SRC_FILES += \ + upstream-openbsd/lib/libc/net/res_random.c \ + +LOCAL_CFLAGS += \ $(libc_common_cflags) \ -DANDROID_CHANGES \ -DINET6 \ @@ -807,6 +828,27 @@ include $(BUILD_STATIC_LIBRARY) # ======================================================== +# libc_cxa.a - Things traditionally in libstdc++ +# ======================================================== + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(libc_cxa_src_files) +LOCAL_CFLAGS := $(libc_common_cflags) \ + -fvisibility=hidden \ + +LOCAL_CONLYFLAGS := $(libc_common_conlyflags) +LOCAL_CPPFLAGS := $(libc_common_cppflags) +LOCAL_C_INCLUDES := $(libc_common_c_includes) +LOCAL_MODULE := libc_cxa +LOCAL_CLANG := true # GCC refuses to hide new/delete +LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies) +LOCAL_SYSTEM_SHARED_LIBRARIES := + +include $(BUILD_STATIC_LIBRARY) + + +# ======================================================== # libc_syscalls.a # ======================================================== @@ -858,6 +900,7 @@ LOCAL_CLANG := $(use_clang) LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies) LOCAL_WHOLE_STATIC_LIBRARIES := \ libc_bionic \ + libc_cxa \ libc_dns \ libc_freebsd \ libc_gdtoa \ @@ -1046,7 +1089,6 @@ LOCAL_CPPFLAGS := $(libc_common_cppflags) # Make sure that unwind.h comes from libunwind. LOCAL_C_INCLUDES := \ - external/libunwind/include \ $(libc_common_c_includes) \ LOCAL_SRC_FILES := \ @@ -1062,7 +1104,9 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies) LOCAL_SHARED_LIBRARIES := libc libdl LOCAL_SYSTEM_SHARED_LIBRARIES := -LOCAL_WHOLE_STATIC_LIBRARIES := libunwindbacktrace +# Only need this for arm since libc++ uses its own unwind code that +# doesn't mix with the other default unwind code. +LOCAL_STATIC_LIBRARIES_arm := libc++ LOCAL_ALLOW_UNDEFINED_SYMBOLS := true # Don't install on release build @@ -1105,6 +1149,36 @@ include $(BUILD_SHARED_LIBRARY) endif #!user +# ======================================================== +# libstdc++.so +# ======================================================== +libstdcxx_common_src_files := \ + bionic/__cxa_guard.cpp \ + bionic/__cxa_pure_virtual.cpp \ + bionic/new.cpp \ + bionic/libc_logging.cpp \ + +include $(CLEAR_VARS) +LOCAL_C_INCLUDES := $(libc_common_c_includes) +LOCAL_CFLAGS := $(libc_common_cflags) +LOCAL_SRC_FILES := $(libstdcxx_common_src_files) +LOCAL_MODULE:= libstdc++ +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_SYSTEM_SHARED_LIBRARIES := libc +include $(BUILD_SHARED_LIBRARY) + +# ======================================================== +# libstdc++.a +# ======================================================== +include $(CLEAR_VARS) +LOCAL_C_INCLUDES := $(libc_common_c_includes) +LOCAL_CFLAGS := $(libc_common_cflags) +LOCAL_SRC_FILES := $(libstdcxx_common_src_files) +LOCAL_MODULE:= libstdc++ +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_SYSTEM_SHARED_LIBRARIES := libc +include $(BUILD_STATIC_LIBRARY) + # ======================================================== include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT index 38ae8310a..bfa13b701 100644 --- a/libc/SYSCALLS.TXT +++ b/libc/SYSCALLS.TXT @@ -315,7 +315,7 @@ int __set_tls:__ARM_NR_set_tls(void*) arm int cacheflush:__ARM_NR_cacheflush(long start, long end, long flags) arm # MIPS-specific -int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips,mips64 +int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips int __set_tls:set_thread_area(void*) mips,mips64 # x86-specific diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk index 00be4aed5..70cc8eba6 100644 --- a/libc/arch-arm/arm.mk +++ b/libc/arch-arm/arm.mk @@ -53,7 +53,6 @@ libc_bionic_src_files_arm += \ arch-arm/bionic/atomics_arm.c \ arch-arm/bionic/__bionic_clone.S \ arch-arm/bionic/_exit_with_stack_teardown.S \ - arch-arm/bionic/__get_sp.S \ arch-arm/bionic/libgcc_compat.c \ arch-arm/bionic/memcmp.S \ arch-arm/bionic/_setjmp.S \ diff --git a/libc/arch-arm/bionic/sigsetjmp.S b/libc/arch-arm/bionic/sigsetjmp.S index f9e30eed8..6a25a1216 100644 --- a/libc/arch-arm/bionic/sigsetjmp.S +++ b/libc/arch-arm/bionic/sigsetjmp.S @@ -33,8 +33,6 @@ * SUCH DAMAGE. */ -#define _ALIGN_TEXT .align 0 - #include <private/bionic_asm.h> #include <machine/setjmp.h> diff --git a/libc/arch-arm/include/machine/asm.h b/libc/arch-arm/include/machine/asm.h index 88d16f950..70dbe67f2 100644 --- a/libc/arch-arm/include/machine/asm.h +++ b/libc/arch-arm/include/machine/asm.h @@ -38,9 +38,7 @@ #ifndef _ARM32_ASM_H_ #define _ARM32_ASM_H_ -#ifndef _ALIGN_TEXT -# define _ALIGN_TEXT .align 0 -#endif +#define __bionic_asm_align 0 #undef __bionic_asm_custom_entry #undef __bionic_asm_custom_end diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk index ed991ce60..6c4f6a6e8 100644 --- a/libc/arch-arm64/arm64.mk +++ b/libc/arch-arm64/arm64.mk @@ -29,7 +29,6 @@ libc_common_src_files_arm64 += \ libc_bionic_src_files_arm64 := \ arch-arm64/bionic/__bionic_clone.S \ arch-arm64/bionic/_exit_with_stack_teardown.S \ - arch-arm64/bionic/__get_sp.S \ arch-arm64/bionic/__rt_sigreturn.S \ arch-arm64/bionic/_setjmp.S \ arch-arm64/bionic/setjmp.S \ diff --git a/libc/arch-arm64/include/machine/asm.h b/libc/arch-arm64/include/machine/asm.h index 31b5c63ea..2bea043e9 100644 --- a/libc/arch-arm64/include/machine/asm.h +++ b/libc/arch-arm64/include/machine/asm.h @@ -38,9 +38,7 @@ #ifndef _AARCH64_ASM_H_ #define _AARCH64_ASM_H_ -#ifndef _ALIGN_TEXT -# define _ALIGN_TEXT .align 0 -#endif +#define __bionic_asm_align 0 #undef __bionic_asm_function_type #define __bionic_asm_function_type %function diff --git a/libc/arch-mips/include/machine/asm.h b/libc/arch-mips/include/machine/asm.h index 5eacde3df..cdc79143a 100644 --- a/libc/arch-mips/include/machine/asm.h +++ b/libc/arch-mips/include/machine/asm.h @@ -28,9 +28,7 @@ #ifndef _MIPS64_ASM_H #define _MIPS64_ASM_H -#ifndef _ALIGN_TEXT -# define _ALIGN_TEXT .align 4 -#endif +#define __bionic_asm_align 4 #undef __bionic_asm_custom_entry #undef __bionic_asm_custom_end diff --git a/libc/arch-mips/mips.mk b/libc/arch-mips/mips.mk index 8e415f957..31a1f32fd 100644 --- a/libc/arch-mips/mips.mk +++ b/libc/arch-mips/mips.mk @@ -54,7 +54,6 @@ libc_bionic_src_files_mips += \ arch-mips/bionic/bzero.S \ arch-mips/bionic/cacheflush.cpp \ arch-mips/bionic/_exit_with_stack_teardown.S \ - arch-mips/bionic/__get_sp.S \ arch-mips/bionic/_setjmp.S \ arch-mips/bionic/setjmp.S \ arch-mips/bionic/sigsetjmp.S \ diff --git a/libc/arch-mips/string/mips_strlen.c b/libc/arch-mips/string/mips_strlen.c index 9fb7e6a85..45fc4b4bd 100644 --- a/libc/arch-mips/string/mips_strlen.c +++ b/libc/arch-mips/string/mips_strlen.c @@ -30,6 +30,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <string.h> #include "mips-string-ops.h" #define do_strlen_word(__av) {\ @@ -47,8 +48,8 @@ #define strlen my_strlen #endif -int -strlen (const void *_a) +size_t +strlen (const char *_a) { int cnt = 0; unsigned x; diff --git a/libc/arch-mips64/bionic/__get_sp.S b/libc/arch-mips64/bionic/__get_sp.S deleted file mode 100644 index 5f5d32ef7..000000000 --- a/libc/arch-mips64/bionic/__get_sp.S +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#include <private/bionic_asm.h> - -ENTRY_PRIVATE(__get_sp) - move v0, sp - j ra -END(__get_sp) diff --git a/libc/arch-mips64/bionic/syscall.S b/libc/arch-mips64/bionic/syscall.S index c4fd00995..e3710f8ce 100644 --- a/libc/arch-mips64/bionic/syscall.S +++ b/libc/arch-mips64/bionic/syscall.S @@ -52,7 +52,7 @@ LEAF(syscall,FRAMESZ) #else move a3, a4 move a4, a5 - REG_L a5, FRAMESZ(sp) + move a5, a6 #endif syscall move a0, v0 diff --git a/libc/arch-mips64/include/machine/asm.h b/libc/arch-mips64/include/machine/asm.h index 5eacde3df..cdc79143a 100644 --- a/libc/arch-mips64/include/machine/asm.h +++ b/libc/arch-mips64/include/machine/asm.h @@ -28,9 +28,7 @@ #ifndef _MIPS64_ASM_H #define _MIPS64_ASM_H -#ifndef _ALIGN_TEXT -# define _ALIGN_TEXT .align 4 -#endif +#define __bionic_asm_align 4 #undef __bionic_asm_custom_entry #undef __bionic_asm_custom_end diff --git a/libc/arch-mips64/syscalls/_flush_cache.S b/libc/arch-mips64/syscalls/_flush_cache.S deleted file mode 100644 index 997ccecb0..000000000 --- a/libc/arch-mips64/syscalls/_flush_cache.S +++ /dev/null @@ -1,27 +0,0 @@ -/* Generated by gensyscalls.py. Do not edit. */ - -#include <private/bionic_asm.h> - - .hidden __set_errno - -ENTRY(_flush_cache) - .set push - .set noreorder - li v0, __NR_cacheflush - 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(_flush_cache) diff --git a/libc/arch-x86/atom/string/sse2-wcslen-atom.S b/libc/arch-x86/atom/string/sse2-wcslen-atom.S index 6a6ad519e..2f10db450 100644 --- a/libc/arch-x86/atom/string/sse2-wcslen-atom.S +++ b/libc/arch-x86/atom/string/sse2-wcslen-atom.S @@ -65,21 +65,21 @@ name: \ ENTRY (wcslen) mov STR(%esp), %edx #endif - cmp $0, (%edx) + cmpl $0, (%edx) jz L(exit_tail0) - cmp $0, 4(%edx) + cmpl $0, 4(%edx) jz L(exit_tail1) - cmp $0, 8(%edx) + cmpl $0, 8(%edx) jz L(exit_tail2) - cmp $0, 12(%edx) + cmpl $0, 12(%edx) jz L(exit_tail3) - cmp $0, 16(%edx) + cmpl $0, 16(%edx) jz L(exit_tail4) - cmp $0, 20(%edx) + cmpl $0, 20(%edx) jz L(exit_tail5) - cmp $0, 24(%edx) + cmpl $0, 24(%edx) jz L(exit_tail6) - cmp $0, 28(%edx) + cmpl $0, 28(%edx) jz L(exit_tail7) pxor %xmm0, %xmm0 diff --git a/libc/arch-x86/bionic/__get_sp.S b/libc/arch-x86/bionic/__get_sp.S deleted file mode 100644 index aea6ac62c..000000000 --- a/libc/arch-x86/bionic/__get_sp.S +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#include <private/bionic_asm.h> - -ENTRY_PRIVATE(__get_sp) - mov %esp, %eax - ret -END(__get_sp) diff --git a/libc/arch-x86/include/machine/asm.h b/libc/arch-x86/include/machine/asm.h index 672493d5d..943f9dd54 100644 --- a/libc/arch-x86/include/machine/asm.h +++ b/libc/arch-x86/include/machine/asm.h @@ -49,15 +49,6 @@ #define PIC_GOT(x) x@GOT(%ebx) #define PIC_GOTOFF(x) x@GOTOFF(%ebx) -/* let kernels and others override entrypoint alignment */ -#if !defined(_ALIGN_TEXT) && !defined(_KERNEL) -# ifdef _STANDALONE -# define _ALIGN_TEXT .align 1 -# elif defined __ELF__ -# define _ALIGN_TEXT .align 16 -# else -# define _ALIGN_TEXT .align 4 -# endif -#endif +#define __bionic_asm_align 16 #endif /* !_I386_ASM_H_ */ diff --git a/libc/arch-x86/x86.mk b/libc/arch-x86/x86.mk index 019dc8e81..a14154866 100644 --- a/libc/arch-x86/x86.mk +++ b/libc/arch-x86/x86.mk @@ -25,7 +25,6 @@ libc_bionic_src_files_x86 := \ libc_bionic_src_files_x86 += \ arch-x86/bionic/__bionic_clone.S \ arch-x86/bionic/_exit_with_stack_teardown.S \ - arch-x86/bionic/__get_sp.S \ arch-x86/bionic/_setjmp.S \ arch-x86/bionic/setjmp.S \ arch-x86/bionic/__set_tls.c \ diff --git a/libc/arch-x86_64/bionic/__get_sp.S b/libc/arch-x86_64/bionic/__get_sp.S deleted file mode 100644 index 49a2406e7..000000000 --- a/libc/arch-x86_64/bionic/__get_sp.S +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#include <private/bionic_asm.h> - -ENTRY_PRIVATE(__get_sp) - mov %rsp, %rax - ret -END(__get_sp) diff --git a/libc/arch-x86_64/include/machine/asm.h b/libc/arch-x86_64/include/machine/asm.h index 06da39aae..28cd08f93 100644 --- a/libc/arch-x86_64/include/machine/asm.h +++ b/libc/arch-x86_64/include/machine/asm.h @@ -40,13 +40,6 @@ #define PIC_PLT(x) x@PLT #define PIC_GOT(x) x@GOTPCREL(%rip) -/* let kernels and others override entrypoint alignment */ -#ifndef _ALIGN_TEXT -# ifdef _STANDALONE -# define _ALIGN_TEXT .align 4 -# else -# define _ALIGN_TEXT .align 16 -# endif -#endif +#define __bionic_asm_align 16 #endif /* !_AMD64_ASM_H_ */ diff --git a/libc/arch-x86_64/x86_64.mk b/libc/arch-x86_64/x86_64.mk index 7887c519e..b001b5e98 100644 --- a/libc/arch-x86_64/x86_64.mk +++ b/libc/arch-x86_64/x86_64.mk @@ -30,7 +30,6 @@ libc_common_src_files_x86_64 += \ libc_bionic_src_files_x86_64 := \ arch-x86_64/bionic/__bionic_clone.S \ arch-x86_64/bionic/_exit_with_stack_teardown.S \ - arch-x86_64/bionic/__get_sp.S \ arch-x86_64/bionic/__rt_sigreturn.S \ arch-x86_64/bionic/_setjmp.S \ arch-x86_64/bionic/setjmp.S \ diff --git a/libc/arch-arm64/bionic/__get_sp.S b/libc/bionic/__gnu_basename.cpp index d5e88e973..1eb3f6594 100644 --- a/libc/arch-arm64/bionic/__get_sp.S +++ b/libc/bionic/__gnu_basename.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 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 @@ -26,9 +26,10 @@ * SUCH DAMAGE. */ -#include <private/bionic_asm.h> +#define _GNU_SOURCE 1 +#include <string.h> -ENTRY_PRIVATE(__get_sp) - mov x0, sp - ret -END(__get_sp) +extern "C" const char* __gnu_basename(const char* path) { + const char* last_slash = strrchr(path, '/'); + return (last_slash != NULL) ? last_slash + 1 : path; +} diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp index b8e892e72..f5be41553 100644 --- a/libc/bionic/bionic_systrace.cpp +++ b/libc/bionic/bionic_systrace.cpp @@ -74,7 +74,7 @@ ScopedTrace::ScopedTrace(const char* message) { } if (g_trace_marker_fd == -1) { - g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC); + g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY); if (g_trace_marker_fd == -1) { __libc_fatal("Could not open kernel trace file: %s\n", strerror(errno)); } diff --git a/libc/bionic/clone.cpp b/libc/bionic/clone.cpp index 0a0fdd526..9b5c9e7ae 100644 --- a/libc/bionic/clone.cpp +++ b/libc/bionic/clone.cpp @@ -26,7 +26,7 @@ * SUCH DAMAGE. */ -#define __GNU_SOURCE 1 +#define _GNU_SOURCE 1 #include <sched.h> #include <stdlib.h> #include <stdarg.h> diff --git a/libc/bionic/daemon.c b/libc/bionic/daemon.c deleted file mode 100644 index 8181d169b..000000000 --- a/libc/bionic/daemon.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> - -int daemon( int nochdir, int noclose ) -{ - pid_t pid; - - if ( !nochdir && chdir("/") != 0 ) - return -1; - - if ( !noclose ) - { - int fd = open("/dev/null", O_RDWR); - - if ( fd < 0 ) - return -1; - - if ( dup2( fd, 0 ) < 0 || - dup2( fd, 1 ) < 0 || - dup2( fd, 2 ) < 0 ) - { - close(fd); - return -1; - } - close(fd); - } - - pid = fork(); - if (pid < 0) - return -1; - - if (pid > 0) - _exit(0); - - if ( setsid() < 0 ) - return -1; - - return 0; -} - diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp index d83799afa..698ab6b87 100644 --- a/libc/bionic/debug_mapinfo.cpp +++ b/libc/bionic/debug_mapinfo.cpp @@ -71,7 +71,7 @@ __LIBC_HIDDEN__ mapinfo_t* mapinfo_create(pid_t pid) { struct mapinfo_t* milist = NULL; char data[1024]; // Used to read lines as well as to construct the filename. snprintf(data, sizeof(data), "/proc/%d/maps", pid); - FILE* fp = fopen(data, "r"); + FILE* fp = fopen(data, "re"); if (fp != NULL) { while (fgets(data, sizeof(data), fp) != NULL) { mapinfo_t* mi = parse_maps_line(data); diff --git a/libc/bionic/dirent.cpp b/libc/bionic/dirent.cpp index 7abc7f3ec..5e1c7a565 100644 --- a/libc/bionic/dirent.cpp +++ b/libc/bionic/dirent.cpp @@ -78,7 +78,7 @@ DIR* fdopendir(int fd) { } DIR* opendir(const char* path) { - int fd = open(path, O_RDONLY | O_DIRECTORY); + int fd = open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY); return (fd != -1) ? __allocate_DIR(fd) : NULL; } diff --git a/libc/bionic/dlmalloc.c b/libc/bionic/dlmalloc.c index e89c5d1ff..5853e7c1b 100644 --- a/libc/bionic/dlmalloc.c +++ b/libc/bionic/dlmalloc.c @@ -16,6 +16,7 @@ #include "dlmalloc.h" +#include "malloc.h" #include "private/bionic_prctl.h" #include "private/libc_logging.h" @@ -54,3 +55,25 @@ static void* named_anonymous_mmap(size_t length) { prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map, length, "libc_malloc"); return map; } + +// Since dlmalloc isn't the default, we'll leave this unimplemented for now. If +// we decide we need it later, we can fill it in. +size_t __mallinfo_narenas() { + return 0; +} + +size_t __mallinfo_nbins() { + return 0; +} + +struct mallinfo __mallinfo_arena_info(size_t aidx __unused) { + struct mallinfo mi; + memset(&mi, 0, sizeof(mi)); + return mi; +} + +struct mallinfo __mallinfo_bin_info(size_t aidx __unused, size_t bidx __unused) { + struct mallinfo mi; + memset(&mi, 0, sizeof(mi)); + return mi; +} diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp index ff9940ef7..2a6a03b5d 100644 --- a/libc/bionic/libc_init_common.cpp +++ b/libc/bionic/libc_init_common.cpp @@ -36,7 +36,6 @@ #include <stdlib.h> #include <sys/auxv.h> #include <sys/time.h> -#include <sys/resource.h> #include <unistd.h> #include "private/bionic_auxv.h" @@ -46,7 +45,6 @@ #include "pthread_internal.h" extern "C" abort_msg_t** __abort_message_ptr; -extern "C" uintptr_t __get_sp(void); extern "C" int __system_properties_init(void); extern "C" int __set_tls(void* ptr); extern "C" int __set_tid_address(int* tid_address); @@ -62,17 +60,6 @@ char** environ; // Declared in "private/bionic_ssp.h". uintptr_t __stack_chk_guard = 0; -static size_t get_main_thread_stack_size() { - rlimit stack_limit; - int rlimit_result = getrlimit(RLIMIT_STACK, &stack_limit); - if ((rlimit_result == 0) && - (stack_limit.rlim_cur != RLIM_INFINITY) && - (stack_limit.rlim_cur > PTHREAD_STACK_MIN)) { - return (stack_limit.rlim_cur & ~(PAGE_SIZE - 1)); - } - return PTHREAD_STACK_SIZE_DEFAULT; -} - /* Init TLS for the initial thread. Called by the linker _before_ libc is mapped * in memory. Beware: all writes to libc globals from this function will * apply to linker-private copies and will not be visible from libc later on. @@ -96,16 +83,15 @@ void __libc_init_tls(KernelArgumentBlock& args) { main_thread.tid = __set_tid_address(&main_thread.tid); main_thread.set_cached_pid(main_thread.tid); - // Work out the extent of the main thread's stack. - uintptr_t stack_top = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE; - size_t stack_size = get_main_thread_stack_size(); - void* stack_bottom = reinterpret_cast<void*>(stack_top - stack_size); - // We don't want to free the main thread's stack even when the main thread exits // because things like environment variables with global scope live on it. + // We also can't free the pthread_internal_t itself, since that lives on the main + // thread's stack rather than on the heap. pthread_attr_init(&main_thread.attr); - pthread_attr_setstack(&main_thread.attr, stack_bottom, stack_size); main_thread.attr.flags = PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK | PTHREAD_ATTR_FLAG_MAIN_THREAD; + main_thread.attr.guard_size = 0; // The main thread has no guard page. + main_thread.attr.stack_size = 0; // User code should never see this; we'll compute it when asked. + // TODO: the main thread's sched_policy and sched_priority need to be queried. __init_thread(&main_thread, false); __init_tls(&main_thread); diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp index d0172edaa..49a37628f 100644 --- a/libc/bionic/libc_logging.cpp +++ b/libc/bionic/libc_logging.cpp @@ -29,6 +29,7 @@ #include "../private/libc_logging.h" // Relative path so we can #include this .cpp file for testing. #include "../private/ScopedPthreadMutexLocker.h" +#include <android/set_abort_message.h> #include <assert.h> #include <errno.h> #include <fcntl.h> @@ -74,10 +75,12 @@ struct BufferOutputStream { len = strlen(data); } + total += len; + while (len > 0) { int avail = end_ - pos_; if (avail == 0) { - break; + return; } if (avail > len) { avail = len; @@ -86,11 +89,10 @@ struct BufferOutputStream { pos_ += avail; pos_[0] = '\0'; len -= avail; - total += avail; } } - int total; + size_t total; private: char* buffer_; @@ -108,18 +110,19 @@ struct FdOutputStream { len = strlen(data); } + total += len; + while (len > 0) { int rc = TEMP_FAILURE_RETRY(write(fd_, data, len)); if (rc == -1) { - break; + return; } data += rc; len -= rc; - total += rc; } } - int total; + size_t total; private: int fd_; @@ -629,7 +632,7 @@ static void __libc_fatal(const char* format, va_list args) { // 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); - __android_set_abort_message(msg); + android_set_abort_message(msg); } void __libc_fatal_no_abort(const char* format, ...) { @@ -647,7 +650,7 @@ void __libc_fatal(const char* format, ...) { abort(); } -void __android_set_abort_message(const char* msg) { +void android_set_abort_message(const char* msg) { ScopedPthreadMutexLocker locker(&g_abort_msg_lock); if (__abort_message_ptr == NULL) { diff --git a/libc/bionic/locale.cpp b/libc/bionic/locale.cpp index 4c3fd7f31..ddb49ce6f 100644 --- a/libc/bionic/locale.cpp +++ b/libc/bionic/locale.cpp @@ -92,7 +92,7 @@ static void __locale_init() { g_locale.int_n_sign_posn = CHAR_MAX; } -size_t __mb_cur_max() { +size_t __ctype_get_mb_cur_max() { locale_t l = reinterpret_cast<locale_t>(pthread_getspecific(g_uselocale_key)); if (l == nullptr || l == LC_GLOBAL_LOCALE) { return __bionic_current_locale_is_utf8 ? 4 : 1; diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp index 837dccc5a..df0f997e5 100644 --- a/libc/bionic/malloc_debug_leak.cpp +++ b/libc/bionic/malloc_debug_leak.cpp @@ -385,6 +385,36 @@ extern "C" void* leak_calloc(size_t n_elements, size_t elem_size) { return ptr; } +extern "C" size_t leak_malloc_usable_size(const void* mem) { + if (DebugCallsDisabled()) { + return g_malloc_dispatch->malloc_usable_size(mem); + } + + if (mem == NULL) { + return 0; + } + + // Check the guard to make sure it is valid. + const AllocationEntry* header = const_to_header(mem); + + if (header->guard == MEMALIGN_GUARD) { + // If this is a memalign'd pointer, then grab the header from + // entry. + header = const_to_header(header->entry); + } else if (header->guard != GUARD) { + debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n", + header->guard, header->entry); + return 0; + } + + size_t ret = g_malloc_dispatch->malloc_usable_size(header); + if (ret != 0) { + // The usable area starts at 'mem' and stops at 'header+ret'. + return reinterpret_cast<uintptr_t>(header) + ret - reinterpret_cast<uintptr_t>(mem); + } + return 0; +} + extern "C" void* leak_realloc(void* oldMem, size_t bytes) { if (DebugCallsDisabled()) { return g_malloc_dispatch->realloc(oldMem, bytes); @@ -408,7 +438,7 @@ extern "C" void* leak_realloc(void* oldMem, size_t bytes) { newMem = leak_malloc(bytes); if (newMem != NULL) { - size_t oldSize = header->entry->size & ~SIZE_FLAG_MASK; + size_t oldSize = leak_malloc_usable_size(oldMem); size_t copySize = (oldSize <= bytes) ? oldSize : bytes; memcpy(newMem, oldMem, copySize); leak_free(oldMem); @@ -462,34 +492,6 @@ extern "C" void* leak_memalign(size_t alignment, size_t bytes) { return base; } -extern "C" size_t leak_malloc_usable_size(const void* mem) { - if (DebugCallsDisabled()) { - return g_malloc_dispatch->malloc_usable_size(mem); - } - - if (mem != NULL) { - // Check the guard to make sure it is valid. - const AllocationEntry* header = const_to_header((void*)mem); - - if (header->guard == MEMALIGN_GUARD) { - // If this is a memalign'd pointer, then grab the header from - // entry. - header = const_to_header(header->entry); - } else if (header->guard != GUARD) { - debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n", - header->guard, header->entry); - return 0; - } - - size_t ret = g_malloc_dispatch->malloc_usable_size(header); - if (ret != 0) { - // The usable area starts at 'mem' and stops at 'header+ret'. - return reinterpret_cast<uintptr_t>(header) + ret - reinterpret_cast<uintptr_t>(mem); - } - } - return 0; -} - extern "C" struct mallinfo leak_mallinfo() { return g_malloc_dispatch->mallinfo(); } diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp index b3b604d86..2f4949b12 100644 --- a/libc/bionic/malloc_debug_qemu.cpp +++ b/libc/bionic/malloc_debug_qemu.cpp @@ -606,7 +606,7 @@ extern "C" bool malloc_debug_initialize(HashTable*, const MallocDebug* malloc_di * the memory mapped spaces into writes to an I/O port that emulator * "listens to" on the other end. Note that until we open and map that * device, logging to emulator's stdout will not be available. */ - int fd = open("/dev/qemu_trace", O_RDWR); + int fd = open("/dev/qemu_trace", O_CLOEXEC | O_RDWR); if (fd < 0) { error_log("Unable to open /dev/qemu_trace"); return false; diff --git a/libc/bionic/malloc_info.cpp b/libc/bionic/malloc_info.cpp new file mode 100644 index 000000000..99caedbad --- /dev/null +++ b/libc/bionic/malloc_info.cpp @@ -0,0 +1,94 @@ +/* + * 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 "malloc_info.h" + +#include <errno.h> +#include "private/bionic_macros.h" + +class __LIBC_HIDDEN__ Elem { +public: + // name must be valid throughout lifetime of the object. + explicit Elem(FILE* fp, const char* name, + const char* attr_fmt = nullptr, ...) { + this->fp = fp; + this->name = name; + + fprintf(fp, "<%s", name); + if (attr_fmt != nullptr) { + va_list args; + va_start(args, attr_fmt); + fputc(' ', fp); + vfprintf(fp, attr_fmt, args); + va_end(args); + } + fputc('>', fp); + } + + ~Elem() noexcept { + fprintf(fp, "</%s>", name); + } + + void contents(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vfprintf(fp, fmt, args); + va_end(args); + } + +private: + FILE* fp; + const char* name; + + DISALLOW_COPY_AND_ASSIGN(Elem); +}; + +int malloc_info(int options, FILE* fp) { + if (options != 0) { + errno = EINVAL; + return -1; + } + + Elem root(fp, "malloc", "version=\"jemalloc-1\""); + + // Dump all of the large allocations in the arenas. + for (size_t i = 0; i < __mallinfo_narenas(); i++) { + struct mallinfo mi = __mallinfo_arena_info(i); + if (mi.hblkhd != 0) { + Elem arena_elem(fp, "heap", "nr=\"%d\"", i); + { + Elem(fp, "allocated-large").contents("%zu", mi.ordblks); + Elem(fp, "allocated-huge").contents("%zu", mi.uordblks); + Elem(fp, "allocated-bins").contents("%zu", mi.fsmblks); + + size_t total = 0; + for (size_t j = 0; j < __mallinfo_nbins(); j++) { + struct mallinfo mi = __mallinfo_bin_info(i, j); + if (mi.ordblks != 0) { + Elem bin_elem(fp, "bin", "nr=\"%d\"", j); + Elem(fp, "allocated").contents("%zu", mi.ordblks); + Elem(fp, "nmalloc").contents("%zu", mi.uordblks); + Elem(fp, "ndalloc").contents("%zu", mi.fordblks); + total += mi.ordblks; + } + } + Elem(fp, "bins-total").contents("%zu", total); + } + } + } + + return 0; +} diff --git a/libc/bionic/malloc_info.h b/libc/bionic/malloc_info.h new file mode 100644 index 000000000..5fffae980 --- /dev/null +++ b/libc/bionic/malloc_info.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef LIBC_BIONIC_MALLOC_INFO_H_ +#define LIBC_BIONIC_MALLOC_INFO_H_ + +#include <malloc.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS + +__LIBC_HIDDEN__ size_t __mallinfo_narenas(); +__LIBC_HIDDEN__ size_t __mallinfo_nbins(); +__LIBC_HIDDEN__ struct mallinfo __mallinfo_arena_info(size_t); +__LIBC_HIDDEN__ struct mallinfo __mallinfo_bin_info(size_t, size_t); + +__END_DECLS + +#endif // LIBC_BIONIC_MALLOC_INFO_H_ diff --git a/libc/bionic/new.cpp b/libc/bionic/new.cpp index fcfd1bdf5..cd84c2e30 100644 --- a/libc/bionic/new.cpp +++ b/libc/bionic/new.cpp @@ -38,11 +38,11 @@ void* operator new[](std::size_t size) { return p; } -void operator delete(void* ptr) { +void operator delete(void* ptr) throw() { free(ptr); } -void operator delete[](void* ptr) { +void operator delete[](void* ptr) throw() { free(ptr); } @@ -54,10 +54,10 @@ void* operator new[](std::size_t size, const std::nothrow_t&) { return malloc(size); } -void operator delete(void* ptr, const std::nothrow_t&) { +void operator delete(void* ptr, const std::nothrow_t&) throw() { free(ptr); } -void operator delete[](void* ptr, const std::nothrow_t&) { +void operator delete[](void* ptr, const std::nothrow_t&) throw() { free(ptr); } diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp index e1cd85365..c93970a19 100644 --- a/libc/bionic/pthread_attr.cpp +++ b/libc/bionic/pthread_attr.cpp @@ -28,6 +28,13 @@ #include <pthread.h> +#include <inttypes.h> +#include <stdio.h> +#include <sys/resource.h> + +#include "private/bionic_string_utils.h" +#include "private/ErrnoRestorer.h" +#include "private/libc_logging.h" #include "pthread_internal.h" int pthread_attr_init(pthread_attr_t* attr) { @@ -90,8 +97,8 @@ int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stack_size) { } int pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* stack_size) { - *stack_size = attr->stack_size; - return 0; + void* unused; + return pthread_attr_getstack(attr, &unused, stack_size); } int pthread_attr_setstack(pthread_attr_t* attr, void* stack_base, size_t stack_size) { @@ -106,7 +113,43 @@ int pthread_attr_setstack(pthread_attr_t* attr, void* stack_base, size_t stack_s return 0; } +static int __pthread_attr_getstack_main_thread(void** stack_base, size_t* stack_size) { + ErrnoRestorer errno_restorer; + + rlimit stack_limit; + if (getrlimit(RLIMIT_STACK, &stack_limit) == -1) { + return errno; + } + + // If the current RLIMIT_STACK is RLIM_INFINITY, only admit to an 8MiB stack for sanity's sake. + if (stack_limit.rlim_cur == RLIM_INFINITY) { + stack_limit.rlim_cur = 8 * 1024 * 1024; + } + + // It doesn't matter which thread we are; we're just looking for "[stack]". + FILE* fp = fopen("/proc/self/maps", "re"); + if (fp == NULL) { + return errno; + } + char line[BUFSIZ]; + while (fgets(line, sizeof(line), fp) != NULL) { + if (ends_with(line, " [stack]\n")) { + uintptr_t lo, hi; + if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &lo, &hi) == 2) { + *stack_size = stack_limit.rlim_cur; + *stack_base = reinterpret_cast<void*>(hi - *stack_size); + fclose(fp); + return 0; + } + } + } + __libc_fatal("No [stack] line found in /proc/self/maps!"); +} + int pthread_attr_getstack(const pthread_attr_t* attr, void** stack_base, size_t* stack_size) { + if ((attr->flags & PTHREAD_ATTR_FLAG_MAIN_THREAD) != 0) { + return __pthread_attr_getstack_main_thread(stack_base, stack_size); + } *stack_base = attr->stack_base; *stack_size = attr->stack_size; return 0; @@ -122,9 +165,8 @@ int pthread_attr_getguardsize(const pthread_attr_t* attr, size_t* guard_size) { return 0; } -int pthread_getattr_np(pthread_t thid, pthread_attr_t* attr) { - pthread_internal_t* thread = (pthread_internal_t*) thid; - *attr = thread->attr; +int pthread_getattr_np(pthread_t t, pthread_attr_t* attr) { + *attr = reinterpret_cast<pthread_internal_t*>(t)->attr; return 0; } diff --git a/libc/bionic/pthread_setname_np.cpp b/libc/bionic/pthread_setname_np.cpp index 1ddf81044..7b2fa6b0a 100644 --- a/libc/bionic/pthread_setname_np.cpp +++ b/libc/bionic/pthread_setname_np.cpp @@ -67,7 +67,7 @@ int pthread_setname_np(pthread_t t, const char* thread_name) { } char comm_name[sizeof(TASK_COMM_FMT) + 8]; snprintf(comm_name, sizeof(comm_name), TASK_COMM_FMT, tid); - int fd = open(comm_name, O_WRONLY); + int fd = open(comm_name, O_CLOEXEC | O_WRONLY); if (fd == -1) { return errno; } diff --git a/libc/bionic/pututline.c b/libc/bionic/pututline.c index c8427f720..8cbf47057 100644 --- a/libc/bionic/pututline.c +++ b/libc/bionic/pututline.c @@ -36,7 +36,7 @@ void pututline(struct utmp* utmp) struct utmp u; long i; - if (!(f = fopen(_PATH_UTMP, "w+"))) + if (!(f = fopen(_PATH_UTMP, "w+e"))) return; while (fread(&u, sizeof(struct utmp), 1, f) == 1) @@ -55,7 +55,7 @@ void pututline(struct utmp* utmp) fclose(f); - if (!(f = fopen(_PATH_UTMP, "w+"))) + if (!(f = fopen(_PATH_UTMP, "w+e"))) return; fwrite(utmp, sizeof(struct utmp), 1, f); diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp index 1e57cc0b3..d419fb109 100644 --- a/libc/bionic/strerror_r.cpp +++ b/libc/bionic/strerror_r.cpp @@ -1,11 +1,16 @@ /* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */ /* Public Domain <marc@snafu.org> */ +// G++ automatically defines _GNU_SOURCE, which then means that <string.h> +// gives us the GNU variant. +#undef _GNU_SOURCE + +#include <string.h> + #include <errno.h> #include <limits.h> #include <signal.h> #include <stdio.h> -#include <string.h> #include "private/ErrnoRestorer.h" #include "private/libc_logging.h" @@ -62,6 +67,12 @@ int strerror_r(int error_number, char* buf, size_t buf_len) { return 0; } +extern "C" char* __gnu_strerror_r(int error_number, char* buf, size_t buf_len) { + ErrnoRestorer errno_restorer; // The glibc strerror_r doesn't set errno if it truncates... + strerror_r(error_number, buf, buf_len); + return buf; // ...and just returns whatever fit. +} + extern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) { const char* signal_name = __strsignal_lookup(signal_number); if (signal_name != NULL) { diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp index 8309f087a..d8aac4fe0 100644 --- a/libc/bionic/sysconf.cpp +++ b/libc/bionic/sysconf.cpp @@ -95,7 +95,7 @@ static int __sysconf_nprocessors_conf() { } static int __sysconf_nprocessors_onln() { - FILE* fp = fopen("/proc/stat", "r"); + FILE* fp = fopen("/proc/stat", "re"); if (fp == NULL) { return 1; } @@ -118,7 +118,7 @@ static int __sysconf_nprocessors_onln() { } static int __get_meminfo(const char* pattern) { - FILE* fp = fopen("/proc/meminfo", "r"); + FILE* fp = fopen("/proc/meminfo", "re"); if (fp == NULL) { return -1; } diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp index 30081a59d..411d6bf34 100644 --- a/libc/bionic/system_properties.cpp +++ b/libc/bionic/system_properties.cpp @@ -201,14 +201,6 @@ static int map_prop_area_rw() return -1; } - // TODO: Is this really required ? Does android run on any kernels that - // don't support O_CLOEXEC ? - const int ret = fcntl(fd, F_SETFD, FD_CLOEXEC); - if (ret < 0) { - close(fd); - return -1; - } - if (ftruncate(fd, PA_SIZE) < 0) { close(fd); return -1; @@ -271,18 +263,9 @@ static int map_fd_ro(const int fd) { static int map_prop_area() { - int fd(open(property_filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC)); - if (fd >= 0) { - /* For old kernels that don't support O_CLOEXEC */ - const int ret = fcntl(fd, F_SETFD, FD_CLOEXEC); - if (ret < 0) { - close(fd); - return -1; - } - } - + int fd = open(property_filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY); bool close_fd = true; - if ((fd < 0) && (errno == ENOENT)) { + if (fd == -1 && errno == ENOENT) { /* * For backwards compatibility, if the file doesn't * exist, we use the environment to get the file descriptor. @@ -611,6 +594,14 @@ const prop_info *__system_property_find(const char *name) return find_property(root_node(), name, strlen(name), NULL, 0, false); } +// The C11 standard doesn't allow atomic loads from const fields, +// though C++11 does. Fudge it until standards get straightened out. +static inline uint_least32_t load_const_atomic(const atomic_uint_least32_t* s, + memory_order mo) { + atomic_uint_least32_t* non_const_s = const_cast<atomic_uint_least32_t*>(s); + return atomic_load_explicit(non_const_s, mo); +} + int __system_property_read(const prop_info *pi, char *name, char *value) { if (__predict_false(compat_mode)) { @@ -631,7 +622,7 @@ int __system_property_read(const prop_info *pi, char *name, char *value) // would be any different, so this should be OK. atomic_thread_fence(memory_order_acquire); if (serial == - atomic_load_explicit(&(pi->serial), memory_order_relaxed)) { + load_const_atomic(&(pi->serial), memory_order_relaxed)) { if (name != 0) { strcpy(name, pi->name); } @@ -733,12 +724,12 @@ int __system_property_add(const char *name, unsigned int namelen, // Wait for non-locked serial, and retrieve it with acquire semantics. unsigned int __system_property_serial(const prop_info *pi) { - uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_acquire); + uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire); while (SERIAL_DIRTY(serial)) { __futex_wait(const_cast<volatile void *>( reinterpret_cast<const void *>(&pi->serial)), serial, NULL); - serial = atomic_load_explicit(&pi->serial, memory_order_acquire); + serial = load_const_atomic(&pi->serial, memory_order_acquire); } return serial; } diff --git a/libc/dns/gethnamaddr.c b/libc/dns/gethnamaddr.c index 80fdcbee1..cc33c612c 100644 --- a/libc/dns/gethnamaddr.c +++ b/libc/dns/gethnamaddr.c @@ -899,7 +899,7 @@ _sethtent(int f) res_static rs = __res_get_static(); if (rs == NULL) return; if (!rs->hostf) - rs->hostf = fopen(_PATH_HOSTS, "r" ); + rs->hostf = fopen(_PATH_HOSTS, "re" ); else rewind(rs->hostf); rs->stayopen = f; @@ -925,7 +925,7 @@ _gethtent(void) int af, len; res_static rs = __res_get_static(); - if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "r" ))) { + if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "re" ))) { h_errno = NETDB_INTERNAL; return NULL; } diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c index 65fd1c197..a4923187e 100644 --- a/libc/dns/net/getaddrinfo.c +++ b/libc/dns/net/getaddrinfo.c @@ -2017,7 +2017,7 @@ _sethtent(FILE **hostf) { if (!*hostf) - *hostf = fopen(_PATH_HOSTS, "r" ); + *hostf = fopen(_PATH_HOSTS, "re"); else rewind(*hostf); } @@ -2046,7 +2046,7 @@ _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) assert(name != NULL); assert(pai != NULL); - if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r" ))) + if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re"))) return (NULL); again: if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) diff --git a/libc/dns/net/services.h b/libc/dns/net/services.h index fa199d084..7f748f79f 100644 --- a/libc/dns/net/services.h +++ b/libc/dns/net/services.h @@ -30,8 +30,8 @@ static const char _services[] = "\ \6tacacs\0\61u\0\ \12re-mail-ck\0\62t\0\ \12re-mail-ck\0\62u\0\ -\6domain\0\65t\1\12nameserver\ -\6domain\0\65u\1\12nameserver\ +\6domain\0\65t\0\ +\6domain\0\65u\0\ \3mtp\0\71t\0\ \11tacacs-ds\0\101t\0\ \11tacacs-ds\0\101u\0\ @@ -44,8 +44,8 @@ static const char _services[] = "\ \6gopher\0\106u\0\ \3rje\0\115t\1\6netrjs\ \6finger\0\117t\0\ -\3www\0\120t\1\4http\ -\3www\0\120u\0\ +\4http\0\120t\1\3www\ +\4http\0\120u\0\ \4link\0\127t\1\7ttylink\ \10kerberos\0\130t\3\11kerberos5\4krb5\14kerberos-sec\ \10kerberos\0\130u\3\11kerberos5\4krb5\14kerberos-sec\ @@ -138,12 +138,16 @@ static const char _services[] = "\ \4ldap\1\205u\0\ \4imsp\1\226t\0\ \4imsp\1\226u\0\ +\6svrloc\1\253t\0\ +\6svrloc\1\253u\0\ \5https\1\273t\0\ \5https\1\273u\0\ \4snpp\1\274t\0\ \4snpp\1\274u\0\ \14microsoft-ds\1\275t\0\ \14microsoft-ds\1\275u\0\ +\7kpasswd\1\320t\0\ +\7kpasswd\1\320u\0\ \4saft\1\347t\0\ \4saft\1\347u\0\ \6isakmp\1\364t\0\ @@ -158,6 +162,8 @@ static const char _services[] = "\ \10npmp-gui\2\143u\1\14dqs313_execd\ \10hmmp-ind\2\144t\1\20dqs313_intercell\ \10hmmp-ind\2\144u\1\20dqs313_intercell\ +\4qmqp\2\164t\0\ +\4qmqp\2\164u\0\ \3ipp\2\167t\0\ \3ipp\2\167u\0\ \4exec\2\0t\0\ @@ -181,8 +187,14 @@ static const char _services[] = "\ \4uucp\2\34t\1\5uucpd\ \6klogin\2\37t\0\ \6kshell\2\40t\1\5krcmd\ +\15dhcpv6-client\2\42t\0\ +\15dhcpv6-client\2\42u\0\ +\15dhcpv6-server\2\43t\0\ +\15dhcpv6-server\2\43u\0\ \12afpovertcp\2\44t\0\ \12afpovertcp\2\44u\0\ +\4idfp\2\45t\0\ +\4idfp\2\45u\0\ \10remotefs\2\54t\2\12rfs_server\3rfs\ \5nntps\2\63t\1\5snntp\ \5nntps\2\63u\1\5snntp\ @@ -239,19 +251,33 @@ static const char _services[] = "\ \13sa-msg-port\6\156u\1\13old-radacct\ \6kermit\6\161t\0\ \6kermit\6\161u\0\ +\11groupwise\6\215t\0\ +\11groupwise\6\215u\0\ \3l2f\6\245t\1\4l2tp\ \3l2f\6\245u\1\4l2tp\ \6radius\7\24t\0\ \6radius\7\24u\0\ \13radius-acct\7\25t\1\7radacct\ \13radius-acct\7\25u\1\7radacct\ +\4msnp\7\107t\0\ +\4msnp\7\107u\0\ \13unix-status\7\245t\0\ \12log-server\7\246t\0\ \12remoteping\7\247t\0\ +\12cisco-sccp\7\320t\0\ +\12cisco-sccp\7\320u\0\ +\6search\7\332t\1\4ndtp\ +\13pipe-server\7\332t\1\13pipe_server\ \3nfs\10\1t\0\ \3nfs\10\1u\0\ +\6gnunet\10\46t\0\ +\6gnunet\10\46u\0\ \12rtcm-sc104\10\65t\0\ \12rtcm-sc104\10\65u\0\ +\15gsigatekeeper\10\107t\0\ +\15gsigatekeeper\10\107u\0\ +\4gris\10\127t\0\ +\4gris\10\127u\0\ \12cvspserver\11\141t\0\ \12cvspserver\11\141u\0\ \5venus\11\176t\0\ @@ -266,10 +292,14 @@ static const char _services[] = "\ \3mon\12\27u\0\ \4dict\12\104t\0\ \4dict\12\104u\0\ +\15f5-globalsite\12\350t\0\ +\15f5-globalsite\12\350u\0\ +\6gsiftp\12\373t\0\ +\6gsiftp\12\373u\0\ \4gpsd\13\203t\0\ \4gpsd\13\203u\0\ -\6gds_db\13\352t\0\ -\6gds_db\13\352u\0\ +\6gds-db\13\352t\1\6gds_db\ +\6gds-db\13\352u\1\6gds_db\ \5icpv2\14\72t\1\3icp\ \5icpv2\14\72u\1\3icp\ \5mysql\14\352t\0\ @@ -282,24 +312,49 @@ static const char _services[] = "\ \4daap\16\151u\0\ \3svn\16\152t\1\12subversion\ \3svn\16\152u\1\12subversion\ +\5suucp\17\277t\0\ +\5suucp\17\277u\0\ +\6sysrqd\17\376t\0\ +\6sysrqd\17\376u\0\ +\5sieve\20\136t\0\ +\4epmd\21\21t\0\ +\4epmd\21\21u\0\ +\6remctl\21\25t\0\ +\6remctl\21\25u\0\ +\11f5-iquery\21\1t\0\ +\11f5-iquery\21\1u\0\ \3iax\21\331t\0\ \3iax\21\331u\0\ +\3mtn\22\123t\0\ +\3mtn\22\123u\0\ \13radmin-port\23\43t\0\ \13radmin-port\23\43u\0\ \3rfe\23\212u\0\ \3rfe\23\212t\0\ +\4mmcc\23\272t\0\ +\4mmcc\23\272u\0\ \3sip\23\304t\0\ \3sip\23\304u\0\ \7sip-tls\23\305t\0\ \7sip-tls\23\305u\0\ +\3aol\24\106t\0\ +\3aol\24\106u\0\ \13xmpp-client\24\146t\1\15jabber-client\ \13xmpp-client\24\146u\1\15jabber-client\ \13xmpp-server\24\225t\1\15jabber-server\ \13xmpp-server\24\225u\1\15jabber-server\ \10cfengine\24\274t\0\ \10cfengine\24\274u\0\ +\4mdns\24\351t\0\ +\4mdns\24\351u\0\ \12postgresql\25\70t\1\10postgres\ \12postgresql\25\70u\1\10postgres\ +\7freeciv\25\264t\1\4rptp\ +\7freeciv\25\264u\0\ +\4amqp\26\50t\0\ +\4amqp\26\50u\0\ +\3ggz\26\70t\0\ +\3ggz\26\70u\0\ \3x11\27\160t\1\5x11-0\ \3x11\27\160u\1\5x11-0\ \5x11-1\27\161t\0\ @@ -320,6 +375,12 @@ static const char _services[] = "\ \14gnutella-svc\30\312u\0\ \14gnutella-rtr\30\313t\0\ \14gnutella-rtr\30\313u\0\ +\13sge-qmaster\31\54t\1\13sge_qmaster\ +\13sge-qmaster\31\54u\1\13sge_qmaster\ +\11sge-execd\31\55t\1\11sge_execd\ +\11sge-execd\31\55u\1\11sge_execd\ +\13mysql-proxy\31\56t\0\ +\13mysql-proxy\31\56u\0\ \17afs3-fileserver\33\130t\1\3bbs\ \17afs3-fileserver\33\130u\1\3bbs\ \15afs3-callback\33\131t\0\ @@ -342,12 +403,21 @@ static const char _services[] = "\ \13afs3-rmtsys\33\141u\0\ \14font-service\33\274t\1\3xfs\ \14font-service\33\274u\1\3xfs\ +\10http-alt\37\220t\1\10webcache\ +\10http-alt\37\220u\0\ \12bacula-dir\43\215t\0\ \12bacula-dir\43\215u\0\ \11bacula-fd\43\216t\0\ \11bacula-fd\43\216u\0\ \11bacula-sd\43\217t\0\ \11bacula-sd\43\217u\0\ +\5xmms2\45\303t\0\ +\5xmms2\45\303u\0\ +\3nbd\52\71t\0\ +\14zabbix-agent\47\102t\0\ +\14zabbix-agent\47\102u\0\ +\16zabbix-trapper\47\103t\0\ +\16zabbix-trapper\47\103u\0\ \6amanda\47\140t\0\ \6amanda\47\140u\0\ \3hkp\54\153t\0\ @@ -364,16 +434,17 @@ static const char _services[] = "\ \4bpcd\65\326u\0\ \6vopied\65\327t\0\ \6vopied\65\327u\0\ +\4dcap\126\155t\0\ +\7gsidcap\126\160t\0\ \4wnn6\127\1t\0\ \4wnn6\127\1u\0\ \11kerberos4\2\356u\2\13kerberos-iv\3kdc\ \11kerberos4\2\356t\2\13kerberos-iv\3kdc\ -\17kerberos_master\2\357u\0\ -\17kerberos_master\2\357t\0\ -\15passwd_server\2\360u\0\ -\10krb_prop\2\362t\2\11krb5_prop\5hprop\ +\17kerberos-master\2\357u\1\17kerberos_master\ +\17kerberos-master\2\357t\0\ +\15passwd-server\2\360u\1\15passwd_server\ +\10krb-prop\2\362t\3\10krb_prop\11krb5_prop\5hprop\ \11krbupdate\2\370t\1\4kreg\ -\7kpasswd\2\371t\1\4kpwd\ \4swat\3\205t\0\ \4kpop\4\125t\0\ \5knetd\10\5t\0\ @@ -389,9 +460,9 @@ static const char _services[] = "\ \10poppassd\0\152t\0\ \10poppassd\0\152u\0\ \5ssmtp\1\321t\1\5smtps\ -\10moira_db\3\7t\0\ -\14moira_update\3\11t\0\ -\12moira_ureg\3\13u\0\ +\10moira-db\3\7t\1\10moira_db\ +\14moira-update\3\11t\1\14moira_update\ +\12moira-ureg\3\13u\1\12moira_ureg\ \5spamd\3\17t\0\ \5omirr\3\50t\1\6omirrd\ \5omirr\3\50u\1\6omirrd\ @@ -404,9 +475,7 @@ static const char _services[] = "\ \4xtel\5\41t\0\ \5xtelw\5\42t\0\ \7support\5\371t\0\ -\5sieve\7\320t\0\ \7cfinger\7\323t\0\ -\4ndtp\7\332t\0\ \4frox\10\111t\0\ \10ninstall\10\146t\0\ \10ninstall\10\146u\0\ @@ -436,9 +505,7 @@ static const char _services[] = "\ \7hostmon\24\353t\0\ \7hostmon\24\353u\0\ \5rplay\25\263u\0\ -\5rplay\25\263t\0\ -\4rptp\25\264u\0\ -\4rptp\25\264t\0\ +\4nrpe\26\42t\0\ \4nsca\26\43t\0\ \4mrtd\26\52t\0\ \6bgpsim\26\53t\0\ @@ -446,14 +513,15 @@ static const char _services[] = "\ \11sane-port\31\246t\2\4sane\5saned\ \4ircd\32\13t\0\ \10zope-ftp\37\125t\0\ -\10webcache\37\220t\0\ \6tproxy\37\221t\0\ \7omniorb\37\230t\0\ \7omniorb\37\230u\0\ \20clc-build-daemon\43\36t\0\ \6xinetd\43\212t\0\ \13mandelspawn\44\217u\1\12mandelbrot\ +\3git\44\312t\0\ \4zope\45\311t\0\ +\6webmin\47\20t\0\ \7kamanda\47\141t\0\ \7kamanda\47\141u\0\ \11amandaidx\47\142t\0\ @@ -473,6 +541,7 @@ static const char _services[] = "\ \5binkp\137\352t\0\ \3asp\152\356t\0\ \3asp\152\356u\0\ +\6csync2\170\221t\0\ \11dircproxy\336\250t\0\ \5tfido\353\21t\0\ \4fido\353\23t\0\ diff --git a/libc/dns/resolv/__dn_comp.c b/libc/dns/resolv/__dn_comp.c deleted file mode 100644 index 93d3f1988..000000000 --- a/libc/dns/resolv/__dn_comp.c +++ /dev/null @@ -1,38 +0,0 @@ -/* $NetBSD: __dn_comp.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */ - -/* - * written by matthew green, 22/04/97. - * public domain. - */ - -#include <sys/cdefs.h> -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: __dn_comp.c,v 1.4 2005/09/13 01:44:10 christos Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#if defined(__indr_reference) -__indr_reference(__dn_comp,dn_comp) -#else - -#include <sys/types.h> -#include <netinet/in.h> -#ifdef ANDROID_CHANGES -#include "resolv_private.h" -#else -#include <resolv.h> -#endif - -/* XXX THIS IS A MESS! SEE <resolv.h> XXX */ - -#undef dn_comp -int dn_comp(const char *, u_char *, int, u_char **, u_char **); - -int -dn_comp(const char *exp_dn, u_char *comp_dn, u_char **dnptrs, - u_char **lastdnptr, int length) -{ - - return __dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr); -} - -#endif diff --git a/libc/dns/resolv/__res_close.c b/libc/dns/resolv/__res_close.c deleted file mode 100644 index 3af50b06b..000000000 --- a/libc/dns/resolv/__res_close.c +++ /dev/null @@ -1,33 +0,0 @@ -/* $NetBSD: __res_close.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */ - -/* - * written by matthew green, 22/04/97. - * public domain. - */ - -#include <sys/cdefs.h> -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: __res_close.c,v 1.4 2005/09/13 01:44:10 christos Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#if defined(__indr_reference) -__indr_reference(__res_close, res_close) -#else - -#include <sys/types.h> -#include <netinet/in.h> -#include "resolv_private.h" - -/* XXX THIS IS A MESS! SEE <resolv.h> XXX */ - -#undef res_close -void res_close(void); - -void -res_close(void) -{ - - __res_close(); -} - -#endif diff --git a/libc/dns/resolv/__res_send.c b/libc/dns/resolv/__res_send.c deleted file mode 100644 index 198b05c12..000000000 --- a/libc/dns/resolv/__res_send.c +++ /dev/null @@ -1,37 +0,0 @@ -/* $NetBSD: __res_send.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */ - -/* - * written by matthew green, 22/04/97. - * public domain. - */ - -#include <sys/cdefs.h> -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: __res_send.c,v 1.4 2005/09/13 01:44:10 christos Exp $"); -#endif - -#if defined(__indr_reference) -__indr_reference(__res_send, res_send) -#else - -#include <sys/types.h> -#include <netinet/in.h> -#ifdef ANDROID_CHANGES -#include "resolv_private.h" -#else -#include <resolv.h> -#endif - -/* XXX THIS IS A MESS! SEE <resolv.h> XXX */ - -#undef res_send -int res_send(const u_char *, int, u_char *, int); - -int -res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) -{ - - return __res_send(buf, buflen, ans, anssiz); -} - -#endif diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c index 77a1b4d19..0201aa8f1 100644 --- a/libc/dns/resolv/res_cache.c +++ b/libc/dns/resolv/res_cache.c @@ -1436,7 +1436,7 @@ _dump_answer(const void* answer, int answerlen) char* buf; int fileLen; - fp = fopen("/data/reslog.txt", "w+"); + fp = fopen("/data/reslog.txt", "w+e"); if (fp != NULL) { statep = __res_get_state(); diff --git a/libc/dns/resolv/res_init.c b/libc/dns/resolv/res_init.c index f1cbed8ac..713b6e015 100644 --- a/libc/dns/resolv/res_init.c +++ b/libc/dns/resolv/res_init.c @@ -289,7 +289,7 @@ __res_vinit(res_state statp, int preinit) { line[sizeof(name) - 1] == '\t')) nserv = 0; - if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { + if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) { /* read the config file */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ @@ -616,47 +616,6 @@ net_mask(struct in_addr in) /*!< XXX - should really use system's version of thi } #endif -#ifdef ANDROID_CHANGES -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 | O_CLOEXEC); - if (random_device < 0) { - return -1; - } - - /* read from the random device, returning -1 on failure (or too many retries)*/ - for (u_int retry = 5; retry > 0; retry--) { - int retval = read(random_device, random_value, sizeof(u_int)); - if (retval == sizeof(u_int)) { - *random_value &= 0xffff; - close(random_device); - return 0; - } else if ((retval < 0) && (errno != EINTR)) { - break; - } - } - - close(random_device); - return -1; -} -#endif /* ANDROID_CHANGES */ - -u_int -res_randomid(void) { -#ifdef ANDROID_CHANGES - int status = 0; - u_int output = 0; - status = real_randomid(&output); - if (status != -1) { - return output; - } -#endif /* ANDROID_CHANGES */ - struct timeval now; - gettimeofday(&now, NULL); - return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); -} - /*% * This routine is for closing the socket if a virtual circuit is used and * the program wants to close it. This provides support for endhostent() diff --git a/libc/arch-arm/bionic/__get_sp.S b/libc/include/android/set_abort_message.h index 9ae6f247f..4b3d82b37 100644 --- a/libc/arch-arm/bionic/__get_sp.S +++ b/libc/include/android/set_abort_message.h @@ -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 @@ -26,9 +26,15 @@ * SUCH DAMAGE. */ -#include <private/bionic_asm.h> +#ifndef _SET_ABORT_MESSAGE_H +#define _SET_ABORT_MESSAGE_H -ENTRY_PRIVATE(__get_sp) - mov r0, sp - bx lr -END(__get_sp) +#include <sys/cdefs.h> + +__BEGIN_DECLS + +void android_set_abort_message(const char* msg); + +__END_DECLS + +#endif // _SET_ABORT_MESSAGE_H diff --git a/libc/include/arpa/inet.h b/libc/include/arpa/inet.h index 067be1fe9..86265bf24 100644 --- a/libc/include/arpa/inet.h +++ b/libc/include/arpa/inet.h @@ -25,6 +25,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #ifndef _ARPA_INET_H_ #define _ARPA_INET_H_ @@ -34,8 +35,6 @@ __BEGIN_DECLS -typedef uint32_t in_addr_t; - in_addr_t inet_addr(const char*); int inet_aton(const char*, struct in_addr*); in_addr_t inet_lnaof(struct in_addr); diff --git a/libc/include/elf.h b/libc/include/elf.h index faae73e92..7a9485aea 100644 --- a/libc/include/elf.h +++ b/libc/include/elf.h @@ -80,6 +80,4 @@ typedef struct { #define STT_LOPROC 13 #define STT_HIPROC 15 -#define R_386_IRELATIVE 42 - #endif /* _ELF_H */ diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h index 4450bb65f..32557d958 100644 --- a/libc/include/fcntl.h +++ b/libc/include/fcntl.h @@ -82,9 +82,9 @@ extern ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int); #if defined(__BIONIC_FORTIFY) extern int __open_2(const char*, int); -extern int __open_real(const char*, int, ...) __asm__(__USER_LABEL_PREFIX__ "open"); +extern int __open_real(const char*, int, ...) __RENAME(open); extern int __openat_2(int, const char*, int); -extern int __openat_real(int, const char*, int, ...) __asm__(__USER_LABEL_PREFIX__ "openat"); +extern int __openat_real(int, const char*, int, ...) __RENAME(openat); __errordecl(__creat_missing_mode, "called with O_CREAT, but missing mode"); __errordecl(__creat_too_many_args, "too many arguments"); diff --git a/libc/include/features.h b/libc/include/features.h index 343c84d2b..a279c7f0e 100644 --- a/libc/include/features.h +++ b/libc/include/features.h @@ -25,34 +25,11 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #ifndef _FEATURES_H_ #define _FEATURES_H_ -/* certain Linux-specific programs expect a <features.h> header file - * that defines various features macros - */ - -/* we do include a number of BSD extensions */ -#define _BSD_SOURCE 1 - -/* we do include a number of GNU extensions */ -#define _GNU_SOURCE 1 - -/* C95 support */ -#undef __USE_ISOC95 -#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199409L -# define __USE_ISOC95 1 -#endif - -/* C99 support */ -#undef __USE_ISOC99 -#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L -# define __USE_ISOC99 1 -#endif - -/* Posix support */ -#define __USE_POSIX 1 -#define __USE_POSIX2 1 -#define __USE_XPG 1 +/* Our <features.h> macro fun is all in <sys/cdefs.h>. */ +#include <sys/cdefs.h> #endif /* _FEATURES_H_ */ diff --git a/libc/include/libgen.h b/libc/include/libgen.h index c5fc76a79..4caf8b9c5 100644 --- a/libc/include/libgen.h +++ b/libc/include/libgen.h @@ -25,6 +25,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #ifndef _LIBGEN_H #define _LIBGEN_H @@ -33,9 +34,18 @@ __BEGIN_DECLS +#if !defined(__bionic_using_gnu_basename) +/* + * <string.h> gets you the GNU basename. + * <libgen.h> the POSIX one. + * Note that our "POSIX" one has the wrong argument cv-qualifiers. + */ +extern char* basename(const char*); +#define __bionic_using_posix_basename +#endif + /* our version of dirname/basename don't modify the input path */ extern char* dirname (const char* path); -extern char* basename(const char* path); /* special thread-safe Bionic versions * diff --git a/libc/include/malloc.h b/libc/include/malloc.h index e6ea27606..cb1dd3bcf 100644 --- a/libc/include/malloc.h +++ b/libc/include/malloc.h @@ -24,6 +24,7 @@ */ #include <sys/cdefs.h> #include <stddef.h> +#include <stdio.h> __BEGIN_DECLS @@ -53,6 +54,27 @@ struct mallinfo { extern struct mallinfo mallinfo(void); +/* + * XML structure for malloc_info(3) is in the following format: + * + * <malloc version="jemalloc-1"> + * <heap nr="INT"> + * <allocated-large>INT</allocated-large> + * <allocated-huge>INT</allocated-huge> + * <allocated-bins>INT</allocated-bins> + * <bins-total>INT</bins-total> + * <bin nr="INT"> + * <allocated>INT</allocated> + * <nmalloc>INT</nmalloc> + * <ndalloc>INT</ndalloc> + * </bin> + * <!-- more bins --> + * </heap> + * <!-- more heaps --> + * </malloc> + */ +extern int malloc_info(int, FILE *); + __END_DECLS #endif /* LIBC_INCLUDE_MALLOC_H_ */ diff --git a/libc/include/netinet/in.h b/libc/include/netinet/in.h index bf3b498c4..44c7fc1a6 100644 --- a/libc/include/netinet/in.h +++ b/libc/include/netinet/in.h @@ -25,6 +25,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #ifndef _NETINET_IN_H_ #define _NETINET_IN_H_ @@ -43,6 +44,9 @@ __BEGIN_DECLS #define INET_ADDRSTRLEN 16 +typedef uint16_t in_port_t; +typedef uint32_t in_addr_t; + extern int bindresvport (int sd, struct sockaddr_in *sin); static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; diff --git a/libc/include/sched.h b/libc/include/sched.h index e43b6ccaa..6155ab7ca 100644 --- a/libc/include/sched.h +++ b/libc/include/sched.h @@ -52,7 +52,7 @@ extern int sched_setparam(pid_t, const struct sched_param*); extern int sched_getparam(pid_t, struct sched_param*); extern int sched_rr_get_interval(pid_t, struct timespec*); -#ifdef _GNU_SOURCE +#if defined(__USE_GNU) extern int clone(int (*)(void*), void*, int, void*, ...); extern int unshare(int); @@ -146,7 +146,7 @@ extern void __sched_cpufree(cpu_set_t* set); extern int __sched_cpucount(size_t setsize, cpu_set_t* set); -#endif /* _GNU_SOURCE */ +#endif /* __USE_GNU */ __END_DECLS diff --git a/libc/include/stdatomic.h b/libc/include/stdatomic.h index 669cefd66..3db25a78e 100644 --- a/libc/include/stdatomic.h +++ b/libc/include/stdatomic.h @@ -31,17 +31,142 @@ #define _STDATOMIC_H_ #include <sys/cdefs.h> + + +#if defined(__cplusplus) && defined(_USING_LIBCXX) +# ifdef __clang__ +# if __has_feature(cxx_atomic) +# define _STDATOMIC_HAVE_ATOMIC +# endif +# else /* gcc */ +# if __GNUC_PREREQ(4, 7) +# define _STDATOMIC_HAVE_ATOMIC +# endif +# endif +#endif + +#ifdef _STDATOMIC_HAVE_ATOMIC + +/* We have a usable C++ <atomic>; use it instead. */ + +#include <atomic> + +#undef _Atomic + /* Also defined by <atomic> for gcc. But not used in macros. */ + /* Also a clang intrinsic. */ + /* Should not be used by client code before this file is */ + /* included. The definitions in <atomic> themselves see */ + /* the old definition, as they should. */ + /* Client code sees the following definition. */ + +#define _Atomic(t) std::atomic<t> + +using std::atomic_is_lock_free; +using std::atomic_init; +using std::atomic_store; +using std::atomic_store_explicit; +using std::atomic_load; +using std::atomic_load_explicit; +using std::atomic_exchange; +using std::atomic_exchange_explicit; +using std::atomic_compare_exchange_strong; +using std::atomic_compare_exchange_strong_explicit; +using std::atomic_compare_exchange_weak; +using std::atomic_compare_exchange_weak_explicit; +using std::atomic_fetch_add; +using std::atomic_fetch_add_explicit; +using std::atomic_fetch_sub; +using std::atomic_fetch_sub_explicit; +using std::atomic_fetch_or; +using std::atomic_fetch_or_explicit; +using std::atomic_fetch_xor; +using std::atomic_fetch_xor_explicit; +using std::atomic_fetch_and; +using std::atomic_fetch_and_explicit; +using std::atomic_thread_fence; +using std::atomic_signal_fence; + +using std::memory_order; +using std::memory_order_relaxed; +using std::memory_order_consume; +using std::memory_order_release; +using std::memory_order_acq_rel; +using std::memory_order_seq_cst; + +using std::atomic_bool; +using std::atomic_char; +using std::atomic_schar; +using std::atomic_uchar; +using std::atomic_short; +using std::atomic_ushort; +using std::atomic_int; +using std::atomic_uint; +using std::atomic_long; +using std::atomic_ulong; +using std::atomic_llong; +using std::atomic_ullong; +using std::atomic_char16_t; +using std::atomic_char32_t; +using std::atomic_wchar_t; +using std::atomic_int_least8_t; +using std::atomic_uint_least8_t; +using std::atomic_int_least16_t; +using std::atomic_uint_least16_t; +using std::atomic_int_least32_t; +using std::atomic_uint_least32_t; +using std::atomic_int_least64_t; +using std::atomic_uint_least64_t; +using std::atomic_int_fast8_t; +using std::atomic_uint_fast8_t; +using std::atomic_int_fast16_t; +using std::atomic_uint_fast16_t; +using std::atomic_int_fast32_t; +using std::atomic_uint_fast32_t; +using std::atomic_int_fast64_t; +using std::atomic_uint_fast64_t; +using std::atomic_intptr_t; +using std::atomic_uintptr_t; +using std::atomic_size_t; +using std::atomic_ptrdiff_t; +using std::atomic_intmax_t; +using std::atomic_uintmax_t; + +#else /* <atomic> unavailable, possibly because this is C, not C++ */ + #include <sys/types.h> #include <stdbool.h> -#if __has_extension(c_atomic) || __has_extension(cxx_atomic) -#define __CLANG_ATOMICS -#elif __GNUC_PREREQ__(4, 7) -#define __GNUC_ATOMICS -#elif defined(__GNUC__) -#define __SYNC_ATOMICS +/* + * C: Do it ourselves. + * Note that the runtime representation defined here should be compatible + * with the C++ one, i.e. an _Atomic(T) needs to contain the same + * bits as a T. + */ + +#include <stddef.h> /* For ptrdiff_t. */ +#include <stdint.h> /* TODO: Should pollute namespace less. */ +#if __STDC_VERSION__ >= 201112L +# include <uchar.h> /* For char16_t and char32_t. */ +#endif + +#ifdef __clang__ +# if __has_extension(c_atomic) || __has_extension(cxx_atomic) +# define __CLANG_ATOMICS +# else +# error "stdatomic.h does not support your compiler" +# endif +# if __has_builtin(__sync_swap) +# define __HAS_BUILTIN_SYNC_SWAP +# endif #else -#error "stdatomic.h does not support your compiler" +# if __GNUC_PREREQ(4, 7) +# define __GNUC_ATOMICS +# else +# define __SYNC_ATOMICS +# ifdef __cplusplus +# define __ATOMICS_AVOID_DOT_INIT +# endif +# endif #endif /* @@ -50,33 +175,53 @@ #ifdef __GCC_ATOMIC_BOOL_LOCK_FREE #define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_BOOL_LOCK_FREE 2 /* For all modern platforms */ #endif #ifdef __GCC_ATOMIC_CHAR_LOCK_FREE #define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_CHAR_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_CHAR16_T_LOCK_FREE #define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_CHAR16_T_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_CHAR32_T_LOCK_FREE #define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_CHAR32_T_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_WCHAR_T_LOCK_FREE #define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_WCHAR_T_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_SHORT_LOCK_FREE #define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_SHORT_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_INT_LOCK_FREE #define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_INT_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_LONG_LOCK_FREE #define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_LONG_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_LLONG_LOCK_FREE #define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_LLONG_LOCK_FREE 1 /* maybe */ #endif #ifdef __GCC_ATOMIC_POINTER_LOCK_FREE #define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_POINTER_LOCK_FREE 2 #endif /* @@ -87,7 +232,11 @@ #define ATOMIC_VAR_INIT(value) (value) #define atomic_init(obj, value) __c11_atomic_init(obj, value) #else +#ifdef __ATOMICS_AVOID_DOT_INIT +#define ATOMIC_VAR_INIT(value) { value } +#else #define ATOMIC_VAR_INIT(value) { .__val = (value) } +#endif #define atomic_init(obj, value) ((void)((obj)->__val = (value))) #endif @@ -121,6 +270,8 @@ * * The memory_order_* constants that denote the barrier behaviour of the * atomic operations. + * The enum values must be identical to those used by the + * C++ <atomic> header. */ typedef enum { @@ -137,7 +288,7 @@ typedef enum { */ static __inline void -atomic_thread_fence(memory_order __order __unused) +atomic_thread_fence(memory_order __order __attribute__((unused))) { #ifdef __CLANG_ATOMICS @@ -150,7 +301,7 @@ atomic_thread_fence(memory_order __order __unused) } static __inline void -atomic_signal_fence(memory_order __order __unused) +atomic_signal_fence(memory_order __order __attribute__((unused))) { #ifdef __CLANG_ATOMICS @@ -172,7 +323,7 @@ atomic_signal_fence(memory_order __order __unused) ((void)(obj), (_Bool)1) #elif defined(__CLANG_ATOMICS) #define atomic_is_lock_free(obj) \ - __atomic_is_lock_free(sizeof(*(obj)), obj) + __c11_atomic_is_lock_free(sizeof(*(obj))) #elif defined(__GNUC_ATOMICS) #define atomic_is_lock_free(obj) \ __atomic_is_lock_free(sizeof((obj)->__val), &(obj)->__val) @@ -185,7 +336,7 @@ atomic_signal_fence(memory_order __order __unused) * 7.17.6 Atomic integer types. */ -#if !__has_extension(c_atomic) && !__has_extension(cxx_atomic) +#ifndef __CLANG_ATOMICS /* * No native support for _Atomic(). Place object in structure to prevent * most forms of direct non-atomic access. @@ -306,7 +457,7 @@ typedef _Atomic(uintmax_t) atomic_uintmax_t; desired, success, failure) \ atomic_compare_exchange_strong_explicit(object, expected, \ desired, success, failure) -#if __has_builtin(__sync_swap) +#ifdef __HAS_BUILTIN_SYNC_SWAP /* Clang provides a full-barrier atomic exchange - use it if available. */ #define atomic_exchange_explicit(object, desired, order) \ ((void)(order), __sync_swap(&(object)->__val, desired)) @@ -386,7 +537,7 @@ typedef struct { atomic_bool __flag; } atomic_flag; -#define ATOMIC_FLAG_INIT { ATOMIC_VAR_INIT(0) } +#define ATOMIC_FLAG_INIT { ATOMIC_VAR_INIT(false) } static __inline bool atomic_flag_test_and_set_explicit(volatile atomic_flag *__object, @@ -419,4 +570,6 @@ atomic_flag_clear(volatile atomic_flag *__object) } #endif /* !_KERNEL */ +#endif /* <atomic> unavailable */ + #endif /* !_STDATOMIC_H_ */ diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 74e573294..ce60fd70e 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -325,6 +325,11 @@ int putc_unlocked(int, FILE *); int putchar_unlocked(int); #endif /* __POSIX_VISIBLE >= 199506 */ +#if __POSIX_VISIBLE >= 200809 +FILE* fmemopen(void*, size_t, const char*); +FILE* open_memstream(char**, size_t*); +#endif /* __POSIX_VISIBLE >= 200809 */ + __END_DECLS #endif /* __BSD_VISIBLE || __POSIX_VISIBLE || __XPG_VISIBLE */ @@ -343,6 +348,11 @@ int setlinebuf(FILE *); int vasprintf(char ** __restrict, const char * __restrict, __va_list) __printflike(2, 0); + +void clearerr_unlocked(FILE*); +int feof_unlocked(FILE*); +int ferror_unlocked(FILE*); + __END_DECLS /* @@ -408,7 +418,7 @@ int sprintf(char *dest, const char *format, ...) #endif extern char* __fgets_chk(char*, int, FILE*, size_t); -extern char* __fgets_real(char*, int, FILE*) __asm__(__USER_LABEL_PREFIX__ "fgets"); +extern char* __fgets_real(char*, int, FILE*) __RENAME(fgets); __errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer"); __errordecl(__fgets_too_small_error, "fgets called with size less than zero"); diff --git a/libc/arch-mips/bionic/__get_sp.S b/libc/include/stdio_ext.h index 5f5d32ef7..f299e54e2 100644 --- a/libc/arch-mips/bionic/__get_sp.S +++ b/libc/include/stdio_ext.h @@ -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 @@ -26,9 +26,29 @@ * SUCH DAMAGE. */ -#include <private/bionic_asm.h> +#ifndef _STDIO_EXT_H +#define _STDIO_EXT_H -ENTRY_PRIVATE(__get_sp) - move v0, sp - j ra -END(__get_sp) +#include <sys/cdefs.h> +#include <stdio.h> + +#define FSETLOCKING_QUERY 0 +#define FSETLOCKING_INTERNAL 1 +#define FSETLOCKING_BYCALLER 2 + +__BEGIN_DECLS + +size_t __fbufsize(FILE*); +int __freading(FILE*); +int __fwriting(FILE*); +int __freadable(FILE*); +int __fwritable(FILE*); +int __flbf(FILE*); +void __fpurge(FILE*); +size_t __fpending(FILE*); +void _flushlbf(void); +int __fsetlocking(FILE*, int); + +__END_DECLS + +#endif /* _STDIO_EXT_H */ diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index a5eb3d15b..52f71dd47 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -161,8 +161,8 @@ extern int mbtowc(wchar_t *, const char *, size_t); extern int wctomb(char *, wchar_t); extern size_t wcstombs(char *, const wchar_t *, size_t); -extern size_t __mb_cur_max(void); -#define MB_CUR_MAX __mb_cur_max() +extern size_t __ctype_get_mb_cur_max(void); +#define MB_CUR_MAX __ctype_get_mb_cur_max() __END_DECLS diff --git a/libc/include/string.h b/libc/include/string.h index 8df68e38d..b0643af6c 100644 --- a/libc/include/string.h +++ b/libc/include/string.h @@ -25,8 +25,9 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#ifndef _STRING_H_ -#define _STRING_H_ + +#ifndef _STRING_H +#define _STRING_H #include <sys/cdefs.h> #include <stddef.h> @@ -66,8 +67,12 @@ extern char* strcasestr(const char *haystack, const char *needle) __purefunc; extern char* strtok(char* __restrict, const char* __restrict); extern char* strtok_r(char* __restrict, const char* __restrict, char** __restrict); -extern char* strerror(int); -extern int strerror_r(int errnum, char *buf, size_t n); +extern char* strerror(int); +#if defined(__USE_GNU) +extern char* strerror_r(int, char*, size_t) __RENAME(__gnu_strerror_r); +#else /* POSIX */ +extern int strerror_r(int, char*, size_t); +#endif extern size_t strnlen(const char *, size_t) __purefunc; extern char* strncat(char* __restrict, const char* __restrict, size_t); @@ -92,6 +97,20 @@ extern size_t strxfrm(char* __restrict, const char* __restrict, size_t); extern int strcoll_l(const char *, const char *, locale_t) __purefunc; extern size_t strxfrm_l(char* __restrict, const char* __restrict, size_t, locale_t); +#if defined(__USE_GNU) && !defined(__bionic_using_posix_basename) +/* + * glibc has a basename in <string.h> that's different to the POSIX one in <libgen.h>. + * It doesn't modify its argument, and in C++ it's const-correct. + */ +#if defined(__cplusplus) +extern "C++" char* basename(char*) __RENAME(__gnu_basename) __nonnull((1)); +extern "C++" const char* basename(const char*) __RENAME(__gnu_basename) __nonnull((1)); +#else +extern char* basename(const char*) __RENAME(__gnu_basename) __nonnull((1)); +#endif +#define __bionic_using_gnu_basename +#endif + #if defined(__BIONIC_FORTIFY) __BIONIC_FORTIFY_INLINE @@ -180,8 +199,7 @@ void* memset(void *s, int c, size_t n) { return __builtin___memset_chk(s, c, n, __bos0(s)); } -extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) - __asm__(__USER_LABEL_PREFIX__ "strlcpy"); +extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcpy); extern size_t __strlcpy_chk(char *, const char *, size_t, size_t); __BIONIC_FORTIFY_INLINE @@ -204,8 +222,7 @@ size_t strlcpy(char* __restrict dest, const char* __restrict src, size_t size) { return __strlcpy_chk(dest, src, size, bos); } -extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t) - __asm__(__USER_LABEL_PREFIX__ "strlcat"); +extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcat); extern size_t __strlcat_chk(char* __restrict, const char* __restrict, size_t, size_t); @@ -291,4 +308,4 @@ char* strrchr(const char *s, int c) { __END_DECLS -#endif /* _STRING_H_ */ +#endif /* _STRING_H */ diff --git a/libc/include/sys/cachectl.h b/libc/include/sys/cachectl.h index 57e6ae787..a302ff806 100644 --- a/libc/include/sys/cachectl.h +++ b/libc/include/sys/cachectl.h @@ -31,6 +31,5 @@ #ifdef __mips__ #include <asm/cachectl.h> extern int __cachectl (void *addr, __const int nbytes, __const int op); -extern int _flush_cache (char *addr, __const int nbytes, __const int op); #endif #endif /* sys/cachectl.h */ diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h index 028661628..b223afd05 100644 --- a/libc/include/sys/cdefs.h +++ b/libc/include/sys/cdefs.h @@ -60,18 +60,18 @@ * or later, for e.g. features that appeared in a particular version * of GNU C. Usage: * - * #if __GNUC_PREREQ__(major, minor) + * #if __GNUC_PREREQ(major, minor) * ...cool feature... * #else * ...delete feature... * #endif */ #ifdef __GNUC__ -#define __GNUC_PREREQ__(x, y) \ +#define __GNUC_PREREQ(x, y) \ ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \ (__GNUC__ > (x))) #else -#define __GNUC_PREREQ__(x, y) 0 +#define __GNUC_PREREQ(x, y) 0 #endif #include <sys/cdefs_elf.h> @@ -163,7 +163,7 @@ * GCC2 provides __extension__ to suppress warnings for various GNU C * language extensions under "-ansi -pedantic". */ -#if !__GNUC_PREREQ__(2, 0) +#if !__GNUC_PREREQ(2, 0) #define __extension__ /* delete __extension__ if non-gcc or gcc1 */ #endif @@ -175,7 +175,7 @@ * these work for GNU C++ (modulo a slight glitch in the C++ grammar * in the distribution version of 2.5.5). */ -#if !__GNUC_PREREQ__(2, 5) +#if !__GNUC_PREREQ(2, 5) #define __attribute__(x) /* delete __attribute__ if non-gcc or gcc1 */ #if defined(__GNUC__) && !defined(__STRICT_ANSI__) #define __dead __volatile @@ -189,7 +189,7 @@ #define __pure #endif -#if __GNUC_PREREQ__(2, 7) +#if __GNUC_PREREQ(2, 7) #define __unused __attribute__((__unused__)) #else #define __unused /* delete */ @@ -197,13 +197,13 @@ #define __pure2 __attribute__((__const__)) /* Android-added: used by FreeBSD libm */ -#if __GNUC_PREREQ__(3, 1) +#if __GNUC_PREREQ(3, 1) #define __used __attribute__((__used__)) #else #define __used /* delete */ #endif -#if __GNUC_PREREQ__(2, 7) +#if __GNUC_PREREQ(2, 7) #define __packed __attribute__((__packed__)) #define __aligned(x) __attribute__((__aligned__(x))) #define __section(x) __attribute__((__section__(x))) @@ -217,11 +217,11 @@ #define __section(x) error: no __section for this compiler #endif -#if !__GNUC_PREREQ__(2, 8) +#if !__GNUC_PREREQ(2, 8) #define __extension__ #endif -#if __GNUC_PREREQ__(2, 8) +#if __GNUC_PREREQ(2, 8) #define __statement(x) __extension__(x) #elif defined(lint) #define __statement(x) (0) @@ -241,7 +241,7 @@ #if defined(__STDC__VERSION__) && __STDC_VERSION__ >= 199901L #define __restrict restrict #else -#if !__GNUC_PREREQ__(2, 92) +#if !__GNUC_PREREQ(2, 92) #define __restrict /* delete __restrict when not supported */ #endif #endif @@ -251,9 +251,9 @@ * in GCC 2.95. */ #if !defined(__STDC_VERSION__) || !(__STDC_VERSION__ >= 199901L) -#if __GNUC_PREREQ__(2, 6) +#if __GNUC_PREREQ(2, 6) #define __func__ __PRETTY_FUNCTION__ -#elif __GNUC_PREREQ__(2, 4) +#elif __GNUC_PREREQ(2, 4) #define __func__ __FUNCTION__ #else #define __func__ "" @@ -267,26 +267,12 @@ #endif /* NO_KERNEL_RCSIDS */ #endif /* _KERNEL */ -#if !defined(_STANDALONE) && !defined(_KERNEL) -#ifdef __GNUC__ -#define __RENAME(x) ___RENAME(x) -#else -#ifdef __lint__ -#define __RENAME(x) __symbolrename(x) -#else -#error "No function renaming possible" -#endif /* __lint__ */ -#endif /* __GNUC__ */ -#else /* _STANDALONE || _KERNEL */ -#define __RENAME(x) no renaming in kernel or standalone environment -#endif - /* * A barrier to stop the optimizer from moving code or assume live * register values. This is gcc specific, the version is more or less * arbitrary, might work with older compilers. */ -#if __GNUC_PREREQ__(2, 95) +#if __GNUC_PREREQ(2, 95) #define __insn_barrier() __asm __volatile("":::"memory") #else #define __insn_barrier() /* */ @@ -320,7 +306,7 @@ * basic block reordering that this affects can often generate * larger code. */ -#if __GNUC_PREREQ__(2, 96) +#if __GNUC_PREREQ(2, 96) #define __predict_true(exp) __builtin_expect((exp) != 0, 1) #define __predict_false(exp) __builtin_expect((exp) != 0, 0) #else @@ -328,7 +314,7 @@ #define __predict_false(exp) (exp) #endif -#if __GNUC_PREREQ__(2, 96) +#if __GNUC_PREREQ(2, 96) #define __noreturn __attribute__((__noreturn__)) #define __mallocfunc __attribute__((malloc)) #define __purefunc __attribute__((pure)) @@ -338,19 +324,19 @@ #define __purefunc #endif -#if __GNUC_PREREQ__(3, 1) +#if __GNUC_PREREQ(3, 1) #define __always_inline __attribute__((__always_inline__)) #else #define __always_inline #endif -#if __GNUC_PREREQ__(3, 4) +#if __GNUC_PREREQ(3, 4) #define __wur __attribute__((__warn_unused_result__)) #else #define __wur #endif -#if __GNUC_PREREQ__(4, 3) +#if __GNUC_PREREQ(4, 3) #define __errordecl(name, msg) extern void name(void) __attribute__((__error__(msg))) #define __warnattr(msg) __attribute__((__warning__(msg))) #else @@ -359,64 +345,33 @@ #endif /* - * Macros for manipulating "link sets". Link sets are arrays of pointers - * to objects, which are gathered up by the linker. - * - * Object format-specific code has provided us with the following macros: - * - * __link_set_add_text(set, sym) - * Add a reference to the .text symbol `sym' to `set'. - * - * __link_set_add_rodata(set, sym) - * Add a reference to the .rodata symbol `sym' to `set'. - * - * __link_set_add_data(set, sym) - * Add a reference to the .data symbol `sym' to `set'. - * - * __link_set_add_bss(set, sym) - * Add a reference to the .bss symbol `sym' to `set'. - * - * __link_set_decl(set, ptype) - * Provide an extern declaration of the set `set', which - * contains an array of the pointer type `ptype'. This - * macro must be used by any code which wishes to reference - * the elements of a link set. - * - * __link_set_start(set) - * This points to the first slot in the link set. - * - * __link_set_end(set) - * This points to the (non-existent) slot after the last - * entry in the link set. - * - * __link_set_count(set) - * Count the number of entries in link set `set'. - * - * In addition, we provide the following macros for accessing link sets: - * - * __link_set_foreach(pvar, set) - * Iterate over the link set `set'. Because a link set is - * an array of pointers, pvar must be declared as "type **pvar", - * and the actual entry accessed as "*pvar". - * - * __link_set_entry(set, idx) - * Access the link set entry at index `idx' from set `set'. + * Some BSD source needs these macros. + * Originally they embedded the rcs versions of each source file + * in the generated binary. We strip strings during build anyway,. */ -#define __link_set_foreach(pvar, set) \ - for (pvar = __link_set_start(set); pvar < __link_set_end(set); pvar++) - -#define __link_set_entry(set, idx) (__link_set_begin(set)[idx]) +#define __IDSTRING(_prefix,_s) /* nothing */ +#define __COPYRIGHT(_s) /* nothing */ +#define __FBSDID(_s) /* nothing */ +#define __RCSID(_s) /* nothing */ +#define __SCCSID(_s) /* nothing */ /* - * Some of the FreeBSD sources used in Bionic need this. - * Originally, this is used to embed the rcs versions of each source file - * in the generated binary. We certainly don't want this in Bionic. + * _BSD_SOURCE and _GNU_SOURCE are expected to be defined by callers before + * any standard header file is included. In those header files we test + * against __USE_BSD and __USE_GNU. glibc does this in <features.h> but we + * do it in <sys/cdefs.h> instead because that's where our existing + * _POSIX_C_SOURCE tests were, and we're already confident that <sys/cdefs.h> + * is included everywhere it should be. */ -#define __FBSDID(s) /* nothing */ +#if defined(_BSD_SOURCE) +# define __USE_BSD 1 +#endif + +#if defined(_GNU_SOURCE) +# define __USE_GNU 1 +#endif /*- - * The following definitions are an extension of the behavior originally - * implemented in <sys/_posix.h>, but with a different level of granularity. * POSIX.1 requires that the macros we test be defined before any standard * header file is included. * @@ -570,11 +525,24 @@ #endif #define __bos0(s) __builtin_object_size((s), 0) -#define __BIONIC_FORTIFY_INLINE \ - extern __inline__ \ - __attribute__ ((always_inline)) \ - __attribute__ ((gnu_inline)) +#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline)) #endif #define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1) +/* Used to tag non-static symbols that are private and never exposed by the shared library. */ +#define __LIBC_HIDDEN__ __attribute__((visibility("hidden"))) + +/* Like __LIBC_HIDDEN__, but preserves binary compatibility for LP32. */ +#ifdef __LP64__ +#define __LIBC64_HIDDEN__ __LIBC_HIDDEN__ +#else +#define __LIBC64_HIDDEN__ __LIBC_ABI_PUBLIC__ +#endif + +/* Used to tag non-static symbols that are public and exposed by the shared library. */ +#define __LIBC_ABI_PUBLIC__ __attribute__((visibility ("default"))) + +/* Used to rename functions so that the compiler emits a call to 'x' rather than the function this was applied to. */ +#define __RENAME(x) __asm__(#x) + #endif /* !_SYS_CDEFS_H_ */ diff --git a/libc/include/sys/cdefs_elf.h b/libc/include/sys/cdefs_elf.h index 4dd7dc347..a40a867b8 100644 --- a/libc/include/sys/cdefs_elf.h +++ b/libc/include/sys/cdefs_elf.h @@ -30,27 +30,9 @@ #ifndef _SYS_CDEFS_ELF_H_ #define _SYS_CDEFS_ELF_H_ -#ifdef __LEADING_UNDERSCORE -#define _C_LABEL(x) __CONCAT(_,x) -#define _C_LABEL_STRING(x) "_"x -#else -#define _C_LABEL(x) x -#define _C_LABEL_STRING(x) x -#endif - -#define ___RENAME(x) __asm__(___STRING(_C_LABEL(x))) - -#define __indr_reference(sym,alias) /* nada, since we do weak refs */ - -#define __strong_alias(alias,sym) \ - __asm__(".global " _C_LABEL_STRING(#alias) "\n" \ - _C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym)); - -#define __weak_alias(alias,sym) \ - __asm__(".weak " _C_LABEL_STRING(#alias) "\n" \ - _C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym)); -#define __weak_extern(sym) \ - __asm__(".weak " _C_LABEL_STRING(#sym)); +#define __strong_alias(alias, sym) \ + __asm__(".global " #alias "\n" \ + #alias " = " #sym); /* We use __warnattr instead of __warn_references. * TODO: remove this and put an empty definition in one of the upstream-* compatibility headers. @@ -58,74 +40,4 @@ #define __warn_references(sym,msg) \ /*__asm__(".section .gnu.warning." #sym "\n\t.ascii \"" msg "\"\n\t.text");*/ -#define __SECTIONSTRING(_sec, _str) \ - __asm__(".section " #_sec "\n\t.asciz \"" _str "\"\n\t.previous") - -/* Used to tag non-static symbols that are private and never exposed by the shared library. */ -#define __LIBC_HIDDEN__ __attribute__((visibility ("hidden"))) - -/* Like __LIBC_HIDDEN__, but preserves binary compatibility for LP32. */ -#ifdef __LP64__ -#define __LIBC64_HIDDEN__ __LIBC_HIDDEN__ -#else -#define __LIBC64_HIDDEN__ __LIBC_ABI_PUBLIC__ -#endif - -/* Used to tag non-static symbols that are public and exposed by the shared library. */ -#define __LIBC_ABI_PUBLIC__ __attribute__((visibility ("default"))) - -#define __IDSTRING(_n,_s) __SECTIONSTRING(.ident,_s) - -#define __RCSID(_s) __IDSTRING(rcsid,_s) -#define __SCCSID(_s) -#define __SCCSID2(_s) -#if 0 /* XXX userland __COPYRIGHTs have \ns in them */ -#define __COPYRIGHT(_s) __SECTIONSTRING(.copyright,_s) -#else -#define __COPYRIGHT(_s) \ - static const char copyright[] \ - __attribute__((__unused__,__section__(".copyright"))) = _s -#endif - -#define __KERNEL_RCSID(_n, _s) __RCSID(_s) -#define __KERNEL_SCCSID(_n, _s) -#if 0 /* XXX see above */ -#define __KERNEL_COPYRIGHT(_n, _s) __COPYRIGHT(_s) -#else -#define __KERNEL_COPYRIGHT(_n, _s) __SECTIONSTRING(.copyright, _s) -#endif - -#ifndef __lint__ -#define __link_set_make_entry(set, sym) \ - static void const * const __link_set_##set##_sym_##sym \ - __section("link_set_" #set) __used = &sym -#define __link_set_make_entry2(set, sym, n) \ - static void const * const __link_set_##set##_sym_##sym##_##n \ - __section("link_set_" #set) __used = &sym[n] -#else -#define __link_set_make_entry(set, sym) \ - extern void const * const __link_set_##set##_sym_##sym -#define __link_set_make_entry2(set, sym, n) \ - extern void const * const __link_set_##set##_sym_##sym##_##n -#endif /* __lint__ */ - -#define __link_set_add_text(set, sym) __link_set_make_entry(set, sym) -#define __link_set_add_rodata(set, sym) __link_set_make_entry(set, sym) -#define __link_set_add_data(set, sym) __link_set_make_entry(set, sym) -#define __link_set_add_bss(set, sym) __link_set_make_entry(set, sym) -#define __link_set_add_text2(set, sym, n) __link_set_make_entry2(set, sym, n) -#define __link_set_add_rodata2(set, sym, n) __link_set_make_entry2(set, sym, n) -#define __link_set_add_data2(set, sym, n) __link_set_make_entry2(set, sym, n) -#define __link_set_add_bss2(set, sym, n) __link_set_make_entry2(set, sym, n) - -#define __link_set_decl(set, ptype) \ - extern ptype * const __start_link_set_##set[]; \ - extern ptype * const __stop_link_set_##set[] \ - -#define __link_set_start(set) (__start_link_set_##set) -#define __link_set_end(set) (__stop_link_set_##set) - -#define __link_set_count(set) \ - (__link_set_end(set) - __link_set_start(set)) - #endif /* !_SYS_CDEFS_ELF_H_ */ diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h index ae2f2381e..a8840ff46 100644 --- a/libc/include/sys/socket.h +++ b/libc/include/sys/socket.h @@ -294,8 +294,7 @@ __socketcall ssize_t recvfrom(int, void*, size_t, int, const struct sockaddr*, s #if defined(__BIONIC_FORTIFY) __errordecl(__recvfrom_error, "recvfrom called with size bigger than buffer"); extern ssize_t __recvfrom_chk(int, void*, size_t, size_t, int, const struct sockaddr*, socklen_t*); -extern ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*) - __asm__(__USER_LABEL_PREFIX__ "recvfrom"); +extern ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*) __RENAME(recvfrom); __BIONIC_FORTIFY_INLINE ssize_t recvfrom(int fd, void* buf, size_t len, int flags, const struct sockaddr* src_addr, socklen_t* addr_len) { diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h index c0c168b2e..b56ffa423 100644 --- a/libc/include/sys/stat.h +++ b/libc/include/sys/stat.h @@ -25,6 +25,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #ifndef _SYS_STAT_H_ #define _SYS_STAT_H_ @@ -162,7 +163,7 @@ extern mode_t umask(mode_t); #if defined(__BIONIC_FORTIFY) extern mode_t __umask_chk(mode_t); -extern mode_t __umask_real(mode_t) __asm__(__USER_LABEL_PREFIX__ "umask"); +extern mode_t __umask_real(mode_t) __RENAME(umask); __errordecl(__umask_invalid_mode, "umask called with invalid mode"); __BIONIC_FORTIFY_INLINE diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 7fbafdf27..34ae2bcd1 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -25,6 +25,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #ifndef _UNISTD_H_ #define _UNISTD_H_ @@ -112,7 +113,7 @@ extern int chdir(const char *); extern int fchdir(int); extern int rmdir(const char *); extern int pipe(int *); -#ifdef _GNU_SOURCE +#if defined(__USE_GNU) extern int pipe2(int *, int); #endif extern int chroot(const char *); @@ -143,7 +144,7 @@ extern ssize_t pwrite64(int, const void *, size_t, off64_t); extern int dup(int); extern int dup2(int, int); -#ifdef _GNU_SOURCE +#if defined(__USE_GNU) extern int dup3(int, int, int); #endif extern int fcntl(int, int, ...); @@ -201,8 +202,7 @@ extern int tcsetpgrp(int fd, pid_t _pid); extern ssize_t __read_chk(int, void*, size_t, size_t); __errordecl(__read_dest_size_error, "read called with size bigger than destination"); __errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX"); -extern ssize_t __read_real(int, void*, size_t) - __asm__(__USER_LABEL_PREFIX__ "read"); +extern ssize_t __read_real(int, void*, size_t) __RENAME(read); __BIONIC_FORTIFY_INLINE ssize_t read(int fd, void* buf, size_t count) { diff --git a/libc/include/wchar.h b/libc/include/wchar.h index 1898c7e93..ae10d93e6 100644 --- a/libc/include/wchar.h +++ b/libc/include/wchar.h @@ -166,6 +166,7 @@ extern wint_t towctrans(wint_t, wctrans_t); extern wctrans_t wctrans(const char*); #if __POSIX_VISIBLE >= 200809 +FILE* open_wmemstream(wchar_t**, size_t*); wchar_t* wcsdup(const wchar_t*); size_t wcsnlen(const wchar_t*, size_t); #endif diff --git a/libc/kernel/tools/clean_header.py b/libc/kernel/tools/clean_header.py index 660181772..ebebe80f9 100755 --- a/libc/kernel/tools/clean_header.py +++ b/libc/kernel/tools/clean_header.py @@ -199,8 +199,7 @@ if __name__ == "__main__": if opt == '-u': noUpdate = 0 elif opt == '-v': - verbose = 1 - D_setlevel(1) + logging.basicConfig(level=logging.DEBUG) elif opt == '-k': kernel_original_path = arg elif opt == '-d': diff --git a/libc/kernel/tools/cpp.py b/libc/kernel/tools/cpp.py index 2be95320c..0c098de26 100644 --- a/libc/kernel/tools/cpp.py +++ b/libc/kernel/tools/cpp.py @@ -1711,7 +1711,7 @@ def optimize_if01( blocks ): while j < n and not blocks[j].isIf(): j += 1 if j > i: - D2("appending lines %d to %d" % (blocks[i].lineno, blocks[j-1].lineno)) + logging.debug("appending lines %d to %d" % (blocks[i].lineno, blocks[j-1].lineno)) result += blocks[i:j] if j >= n: break @@ -1730,17 +1730,17 @@ def optimize_if01( blocks ): break dir = blocks[j].directive if dir == "endif": - D2("remove 'if 0' .. 'endif' (lines %d to %d)" % (blocks[i].lineno, blocks[j].lineno)) + logging.debug("remove 'if 0' .. 'endif' (lines %d to %d)" % (blocks[i].lineno, blocks[j].lineno)) i = j + 1 elif dir == "else": # convert 'else' into 'if 1' - D2("convert 'if 0' .. 'else' into 'if 1' (lines %d to %d)" % (blocks[i].lineno, blocks[j-1].lineno)) + logging.debug("convert 'if 0' .. 'else' into 'if 1' (lines %d to %d)" % (blocks[i].lineno, blocks[j-1].lineno)) blocks[j].directive = "if" blocks[j].expr = CppExpr( CppLineTokenizer("1").toTokenList() ) i = j elif dir == "elif": # convert 'elif' into 'if' - D2("convert 'if 0' .. 'elif' into 'if'") + logging.debug("convert 'if 0' .. 'elif' into 'if'") blocks[j].directive = "if" i = j continue @@ -1749,25 +1749,25 @@ def optimize_if01( blocks ): k = find_matching_endif( blocks, j+1 ) if k >= n: # unterminated #if 1, finish here - D2("unterminated 'if 1'") + logging.debug("unterminated 'if 1'") result += blocks[j+1:k] break dir = blocks[k].directive if dir == "endif": - D2("convert 'if 1' .. 'endif' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno)) + logging.debug("convert 'if 1' .. 'endif' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno)) result += optimize_if01(blocks[j+1:k]) i = k+1 elif dir == "else": # convert 'else' into 'if 0' - D2("convert 'if 1' .. 'else' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno)) + logging.debug("convert 'if 1' .. 'else' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno)) result += optimize_if01(blocks[j+1:k]) blocks[k].directive = "if" blocks[k].expr = CppExpr( CppLineTokenizer("0").toTokenList() ) i = k elif dir == "elif": # convert 'elif' into 'if 0' - D2("convert 'if 1' .. 'elif' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno)) + logging.debug("convert 'if 1' .. 'elif' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno)) result += optimize_if01(blocks[j+1:k]) blocks[k].expr = CppExpr( CppLineTokenizer("0").toTokenList() ) i = k @@ -1835,7 +1835,6 @@ def test_optimizeAll(): out = StringOutput() lines = string.split(text, '\n') list = BlockParser().parse( CppLinesTokenizer(lines) ) - #D_setlevel(2) list.replaceTokens( kernel_token_replacements ) list.optimizeAll( {"__KERNEL__":kCppUndefinedMacro} ) list.write(out) diff --git a/libc/kernel/tools/utils.py b/libc/kernel/tools/utils.py index 0478e93e6..e5a310e03 100644 --- a/libc/kernel/tools/utils.py +++ b/libc/kernel/tools/utils.py @@ -1,59 +1,29 @@ # common python utility routines for the Bionic tool scripts -import sys, os, commands, string, commands +import commands +import logging +import os +import string +import sys -# basic debugging trace support -# call D_setlevel to set the verbosity level -# and D(), D2(), D3(), D4() to add traces -# -verbose = 0 def panic(msg): - sys.stderr.write( find_program_name() + ": error: " ) - sys.stderr.write( msg ) + sys.stderr.write(os.path.basename(sys.argv[0]) + ": error: ") + sys.stderr.write(msg) sys.exit(1) -def D(msg): - global verbose - if verbose > 0: - print msg - -def D2(msg): - global verbose - if verbose >= 2: - print msg - -def D3(msg): - global verbose - if verbose >= 3: - print msg - -def D4(msg): - global verbose - if verbose >= 4: - print msg - -def D_setlevel(level): - global verbose - verbose = level - - -# other stuff -# -# -def find_program_name(): - return os.path.basename(sys.argv[0]) def find_program_dir(): return os.path.dirname(sys.argv[0]) + class StringOutput: def __init__(self): self.line = "" def write(self,msg): self.line += msg - D2("write '%s'" % msg) + logging.debug("write '%s'" % msg) def get(self): return self.line @@ -76,47 +46,6 @@ def create_file_path(path): continue os.mkdir(dir) -def walk_source_files(paths,callback,args,excludes=[]): - """recursively walk a list of paths and files, only keeping the source files in directories""" - for path in paths: - if len(path) > 0 and path[0] == '@': - # this is the name of another file, include it and parse it - path = path[1:] - if os.path.exists(path): - for line in open(path): - if len(line) > 0 and line[-1] == '\n': - line = line[:-1] - walk_source_files([line],callback,args,excludes) - continue - if not os.path.isdir(path): - callback(path,args) - else: - for root, dirs, files in os.walk(path): - #print "w-- %s (ex: %s)" % (repr((root,dirs)), repr(excludes)) - if len(excludes): - for d in dirs[:]: - if os.path.join(root,d) in excludes: - dirs.remove(d) - for f in files: - r, ext = os.path.splitext(f) - if ext in [ ".h", ".c", ".cpp", ".S" ]: - callback( "%s/%s" % (root,f), args ) - -def cleanup_dir(path): - """create a directory if needed, and ensure that it is totally empty - by removing any existing content in it""" - if not os.path.exists(path): - os.mkdir(path) - else: - for root, dirs, files in os.walk(path, topdown=False): - if root.endswith("kernel_headers/"): - # skip 'kernel_headers' - continue - for name in files: - os.remove(os.path.join(root, name)) - for name in dirs: - os.rmdir(os.path.join(root, name)) - class BatchFileUpdater: """a class used to edit several files at once""" diff --git a/libc/private/bionic_asm.h b/libc/private/bionic_asm.h index 7c2686f38..d53ebbae1 100644 --- a/libc/private/bionic_asm.h +++ b/libc/private/bionic_asm.h @@ -41,7 +41,7 @@ #define ENTRY(f) \ .text; \ .globl f; \ - _ALIGN_TEXT; \ + .align __bionic_asm_align; \ .type f, __bionic_asm_function_type; \ f: \ __bionic_asm_custom_entry(f); \ diff --git a/tests/libs/dlsym_local_symbol_private.cpp b/libc/private/bionic_string_utils.h index 2587508e9..ab0eccf02 100644 --- a/tests/libs/dlsym_local_symbol_private.cpp +++ b/libc/private/bionic_string_utils.h @@ -14,11 +14,18 @@ * limitations under the License. */ -#include <stdlib.h> -#include <dlfcn.h> -#include <stdio.h> +#ifndef _BIONIC_STRING_UTILS_H_ +#define _BIONIC_STRING_UTILS_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; +#include <string.h> + +static inline bool ends_with(const char* s1, const char* s2) { + size_t s1_length = strlen(s1); + size_t s2_length = strlen(s2); + if (s2_length > s1_length) { + return false; + } + return memcmp(s1 + (s1_length - s2_length), s2, s2_length) == 0; +} + +#endif // _BIONIC_STRING_UTILS_H_ diff --git a/libc/private/libc_logging.h b/libc/private/libc_logging.h index 35c756bb9..da2192bba 100644 --- a/libc/private/libc_logging.h +++ b/libc/private/libc_logging.h @@ -69,8 +69,6 @@ struct abort_msg_t { char msg[0]; }; -void __android_set_abort_message(const char* msg); - // // Formats a message to the log (priority 'fatal'), then aborts. // diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp new file mode 100644 index 000000000..bfdecb81c --- /dev/null +++ b/libc/stdio/stdio_ext.cpp @@ -0,0 +1,96 @@ +/* + * 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. + */ + +#include <stdio_ext.h> + +#include <stdio.h> +#include "local.h" + +#define FSETLOCKING_QUERY 0 +#define FSETLOCKING_INTERNAL 1 +#define FSETLOCKING_BYCALLER 2 + +size_t __fbufsize(FILE* fp) { + return fp->_bf._size; +} + +/* For a _SRW stream, we don't know whether we last read or wrote. +int __freading(FILE* fp) { + return (fp->_flags & _SRD) != 0 || ...; +} +*/ + +/* For a _SRW stream, we don't know whether we last read or wrote. +int __fwriting(FILE*) { + return (fp->_flags & _SWR) != 0 || ...; +} +*/ + +int __freadable(FILE* fp) { + return (fp->_flags & (__SRD|__SRW)) != 0; +} + +int __fwritable(FILE* fp) { + return (fp->_flags & (__SWR|__SRW)) != 0; +} + +int __flbf(FILE* fp) { + return (fp->_flags & __SLBF) != 0; +} + +void __fpurge(FILE* fp) { + fpurge(fp); +} + +size_t __fpending(FILE* fp) { + return fp->_p - fp->_bf._base; +} + +void _flushlbf() { + // If we flush all streams, we know we've flushed all the line-buffered streams. + fflush(NULL); +} + +int __fsetlocking(FILE*, int) { + // We don't currently have an implementation that would obey this, + // so make setting the state a no-op and always return "we handle locking for you". + // http://b/17154740 suggests ways we could fix this. + return FSETLOCKING_INTERNAL; +} + +void clearerr_unlocked(FILE* fp) { + return __sclearerr(fp); +} + +int feof_unlocked(FILE* fp) { + return __sfeof(fp); +} + +int ferror_unlocked(FILE* fp) { + return __sferror(fp); +} diff --git a/libc/tools/bionic_utils.py b/libc/tools/bionic_utils.py deleted file mode 100644 index c38efb503..000000000 --- a/libc/tools/bionic_utils.py +++ /dev/null @@ -1,165 +0,0 @@ -# common python utility routines for the Bionic tool scripts - -import sys, os, commands, string - -all_arches = [ "arm", "arm64", "mips", "mips64", "x86", "x86_64" ] - -# basic debugging trace support -# call D_setlevel to set the verbosity level -# and D(), D2(), D3(), D4() to add traces -# -verbose = 0 - -def D(msg): - global verbose - if verbose > 0: - print msg - -def D2(msg): - global verbose - if verbose >= 2: - print msg - -def D3(msg): - global verbose - if verbose >= 3: - print msg - -def D4(msg): - global verbose - if verbose >= 4: - print msg - -def D_setlevel(level): - global verbose - verbose = level - - -# parser for the SYSCALLS.TXT file -# -class SysCallsTxtParser: - def __init__(self): - self.syscalls = [] - self.lineno = 0 - - def E(self, msg): - print "%d: %s" % (self.lineno, msg) - - def parse_line(self, line): - """ parse a syscall spec line. - - line processing, format is - return type func_name[|alias_list][:syscall_name[:socketcall_id]] ( [paramlist] ) architecture_list - """ - pos_lparen = line.find('(') - E = self.E - if pos_lparen < 0: - E("missing left parenthesis in '%s'" % line) - return - - pos_rparen = line.rfind(')') - if pos_rparen < 0 or pos_rparen <= pos_lparen: - E("missing or misplaced right parenthesis in '%s'" % line) - return - - return_type = line[:pos_lparen].strip().split() - if len(return_type) < 2: - E("missing return type in '%s'" % line) - return - - syscall_func = return_type[-1] - return_type = string.join(return_type[:-1],' ') - socketcall_id = -1 - - pos_colon = syscall_func.find(':') - if pos_colon < 0: - syscall_name = syscall_func - else: - if pos_colon == 0 or pos_colon+1 >= len(syscall_func): - E("misplaced colon in '%s'" % line) - return - - # now find if there is a socketcall_id for a dispatch-type syscall - # after the optional 2nd colon - pos_colon2 = syscall_func.find(':', pos_colon + 1) - if pos_colon2 < 0: - syscall_name = syscall_func[pos_colon+1:] - syscall_func = syscall_func[:pos_colon] - else: - if pos_colon2+1 >= len(syscall_func): - E("misplaced colon2 in '%s'" % line) - return - syscall_name = syscall_func[(pos_colon+1):pos_colon2] - socketcall_id = int(syscall_func[pos_colon2+1:]) - syscall_func = syscall_func[:pos_colon] - - alias_delim = syscall_func.find('|') - if alias_delim > 0: - alias_list = syscall_func[alias_delim+1:].strip() - syscall_func = syscall_func[:alias_delim] - alias_delim = syscall_name.find('|') - if alias_delim > 0: - syscall_name = syscall_name[:alias_delim] - syscall_aliases = string.split(alias_list, ',') - else: - syscall_aliases = [] - - if pos_rparen > pos_lparen+1: - syscall_params = line[pos_lparen+1:pos_rparen].split(',') - params = string.join(syscall_params,',') - else: - syscall_params = [] - params = "void" - - t = { - "name" : syscall_name, - "func" : syscall_func, - "aliases" : syscall_aliases, - "params" : syscall_params, - "decl" : "%-15s %s (%s);" % (return_type, syscall_func, params), - "socketcall_id" : socketcall_id - } - - # Parse the architecture list. - arch_list = line[pos_rparen+1:].strip() - if arch_list == "all": - for arch in all_arches: - t[arch] = True - else: - for arch in string.split(arch_list, ','): - if arch in all_arches: - t[arch] = True - else: - E("invalid syscall architecture '%s' in '%s'" % (arch, line)) - return - - self.syscalls.append(t) - - global verbose - if verbose >= 2: - print t - - - def parse_file(self, file_path): - D2("parse_file: %s" % file_path) - fp = open(file_path) - for line in fp.xreadlines(): - self.lineno += 1 - line = line.strip() - if not line: continue - if line[0] == '#': continue - self.parse_line(line) - - fp.close() - - -class StringOutput: - def __init__(self): - self.line = "" - - def write(self,msg): - self.line += msg - D2("write '%s'" % msg) - - def get(self): - return self.line diff --git a/libc/tools/check-symbols-glibc.py b/libc/tools/check-symbols-glibc.py index 58a10e060..8bcf7fcc5 100755 --- a/libc/tools/check-symbols-glibc.py +++ b/libc/tools/check-symbols-glibc.py @@ -3,12 +3,18 @@ import glob import os import re -import string import subprocess import sys +only_unwanted = False +if len(sys.argv) > 1: + if sys.argv[1] in ('-u', '--unwanted'): + only_unwanted = True + toolchain = os.environ['ANDROID_TOOLCHAIN'] arch = re.sub(r'.*/linux-x86/([^/]+)/.*', r'\1', toolchain) +if arch == 'aarch64': + arch = 'arm64' def GetSymbolsFromSo(so_file): # Example readelf output: @@ -50,15 +56,26 @@ def MangleGlibcNameToBionic(name): return glibc_to_bionic_names[name] return name +def GetNdkIgnored(): + global arch + symbols = set() + files = glob.glob('%s/ndk/build/tools/unwanted-symbols/%s/*' % + (os.getenv('ANDROID_BUILD_TOP'), arch)) + for f in files: + symbols |= set(open(f, 'r').read().splitlines()) + return symbols + glibc_to_bionic_names = { '__res_init': 'res_init', '__res_mkquery': 'res_mkquery', '__res_query': 'res_query', '__res_search': 'res_search', + '__xpg_basename': '__gnu_basename', } glibc = GetSymbolsFromSystemSo('libc.so.*', 'librt.so.*', 'libpthread.so.*', 'libresolv.so.*', 'libm.so.*') bionic = GetSymbolsFromAndroidSo('libc.so', 'libm.so') +ndk_ignored = GetNdkIgnored() glibc = map(MangleGlibcNameToBionic, glibc) @@ -100,6 +117,16 @@ macro_stuff = set([ '__errno', '__fe_dfl_env', '__get_h_errno', + '__fpclassifyd', + '__isfinite', + '__isfinitef', + '__isfinitel', + '__isnormal', + '__isnormalf', + '__isnormall', + '__sF', + '__pthread_cleanup_pop', + '__pthread_cleanup_push', ]) # bionic exposes various Linux features that glibc doesn't. linux_stuff = set([ @@ -133,21 +160,43 @@ weird_stuff = set([ 'mknodat', 'stat', 'stat64', + 'optreset', + 'sigsetjmp', +]) +# These exist in glibc, but under slightly different names (generally one extra +# or one fewer _). TODO: check against glibc names. +libresolv_stuff = set([ + '__res_send_setqhook', + '__res_send_setrhook', + '_resolv_flush_cache_for_net', + '_resolv_set_nameservers_for_net', + 'dn_expand', + 'nsdispatch', +]) +# Implementation details we know we export (and can't get away from). +known = set([ + '_ctype_', + '__libc_init', ]) -print 'glibc:' -for symbol in sorted(glibc): - print symbol +if not only_unwanted: + print 'glibc:' + for symbol in sorted(glibc): + print symbol -print -print 'bionic:' -for symbol in sorted(bionic): - print symbol + print + print 'bionic:' + for symbol in sorted(bionic): + print symbol + + print + print 'in bionic but not glibc:' -print -print 'in bionic but not glibc:' -allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff | std_stuff | weird_stuff) +allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff | + std_stuff | weird_stuff | libresolv_stuff | known) for symbol in sorted((bionic - allowed_stuff).difference(glibc)): + if symbol in ndk_ignored: + symbol += '*' print symbol sys.exit(0) diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py index 4619ec690..929bec47e 100755 --- a/libc/tools/gensyscalls.py +++ b/libc/tools/gensyscalls.py @@ -8,14 +8,18 @@ import atexit import commands import filecmp import glob +import logging import os.path import re import shutil import stat +import string import sys import tempfile -from bionic_utils import * + +all_arches = [ "arm", "arm64", "mips", "mips64", "x86", "x86_64" ] + # temp directory where we store all intermediate files bionic_temp = tempfile.mkdtemp(prefix="bionic_gensyscalls"); @@ -387,6 +391,120 @@ def x86_64_genstub(syscall): return result +class SysCallsTxtParser: + def __init__(self): + self.syscalls = [] + self.lineno = 0 + + def E(self, msg): + print "%d: %s" % (self.lineno, msg) + + def parse_line(self, line): + """ parse a syscall spec line. + + line processing, format is + return type func_name[|alias_list][:syscall_name[:socketcall_id]] ( [paramlist] ) architecture_list + """ + pos_lparen = line.find('(') + E = self.E + if pos_lparen < 0: + E("missing left parenthesis in '%s'" % line) + return + + pos_rparen = line.rfind(')') + if pos_rparen < 0 or pos_rparen <= pos_lparen: + E("missing or misplaced right parenthesis in '%s'" % line) + return + + return_type = line[:pos_lparen].strip().split() + if len(return_type) < 2: + E("missing return type in '%s'" % line) + return + + syscall_func = return_type[-1] + return_type = string.join(return_type[:-1],' ') + socketcall_id = -1 + + pos_colon = syscall_func.find(':') + if pos_colon < 0: + syscall_name = syscall_func + else: + if pos_colon == 0 or pos_colon+1 >= len(syscall_func): + E("misplaced colon in '%s'" % line) + return + + # now find if there is a socketcall_id for a dispatch-type syscall + # after the optional 2nd colon + pos_colon2 = syscall_func.find(':', pos_colon + 1) + if pos_colon2 < 0: + syscall_name = syscall_func[pos_colon+1:] + syscall_func = syscall_func[:pos_colon] + else: + if pos_colon2+1 >= len(syscall_func): + E("misplaced colon2 in '%s'" % line) + return + syscall_name = syscall_func[(pos_colon+1):pos_colon2] + socketcall_id = int(syscall_func[pos_colon2+1:]) + syscall_func = syscall_func[:pos_colon] + + alias_delim = syscall_func.find('|') + if alias_delim > 0: + alias_list = syscall_func[alias_delim+1:].strip() + syscall_func = syscall_func[:alias_delim] + alias_delim = syscall_name.find('|') + if alias_delim > 0: + syscall_name = syscall_name[:alias_delim] + syscall_aliases = string.split(alias_list, ',') + else: + syscall_aliases = [] + + if pos_rparen > pos_lparen+1: + syscall_params = line[pos_lparen+1:pos_rparen].split(',') + params = string.join(syscall_params,',') + else: + syscall_params = [] + params = "void" + + t = { + "name" : syscall_name, + "func" : syscall_func, + "aliases" : syscall_aliases, + "params" : syscall_params, + "decl" : "%-15s %s (%s);" % (return_type, syscall_func, params), + "socketcall_id" : socketcall_id + } + + # Parse the architecture list. + arch_list = line[pos_rparen+1:].strip() + if arch_list == "all": + for arch in all_arches: + t[arch] = True + else: + for arch in string.split(arch_list, ','): + if arch in all_arches: + t[arch] = True + else: + E("invalid syscall architecture '%s' in '%s'" % (arch, line)) + return + + self.syscalls.append(t) + + logging.debug(t) + + + def parse_file(self, file_path): + logging.debug("parse_file: %s" % file_path) + fp = open(file_path) + for line in fp.xreadlines(): + self.lineno += 1 + line = line.strip() + if not line: continue + if line[0] == '#': continue + self.parse_line(line) + + fp.close() + + class State: def __init__(self): self.old_stubs = [] @@ -444,7 +562,7 @@ class State: def gen_glibc_syscalls_h(self): # TODO: generate a separate file for each architecture, like glibc's bits/syscall.h. glibc_syscalls_h_path = "include/sys/glibc-syscalls.h" - D("generating " + glibc_syscalls_h_path) + logging.info("generating " + glibc_syscalls_h_path) glibc_fp = create_file(glibc_syscalls_h_path) glibc_fp.write("/* %s */\n" % warning) glibc_fp.write("#ifndef _BIONIC_GLIBC_SYSCALLS_H_\n") @@ -473,7 +591,7 @@ class State: for arch in all_arches: if syscall.has_key("asm-%s" % arch): filename = "arch-%s/syscalls/%s.S" % (arch, syscall["func"]) - D2(">>> generating " + filename) + logging.info(">>> generating " + filename) fp = create_file(filename) fp.write(syscall["asm-%s" % arch]) fp.close() @@ -481,28 +599,28 @@ class State: def regenerate(self): - D("scanning for existing architecture-specific stub files...") + logging.info("scanning for existing architecture-specific stub files...") for arch in all_arches: arch_dir = "arch-" + arch - D("scanning " + os.path.join(bionic_libc_root, arch_dir)) + logging.info("scanning " + os.path.join(bionic_libc_root, arch_dir)) rel_path = os.path.join(arch_dir, "syscalls") for file in os.listdir(os.path.join(bionic_libc_root, rel_path)): if file.endswith(".S"): self.old_stubs.append(os.path.join(rel_path, file)) - D("found %d stub files" % len(self.old_stubs)) + logging.info("found %d stub files" % len(self.old_stubs)) if not os.path.exists(bionic_temp): - D("creating %s..." % bionic_temp) + logging.info("creating %s..." % bionic_temp) make_dir(bionic_temp) - D("re-generating stubs and support files...") + logging.info("re-generating stubs and support files...") self.gen_glibc_syscalls_h() self.gen_syscall_stubs() - D("comparing files...") + logging.info("comparing files...") adds = [] edits = [] @@ -511,18 +629,18 @@ class State: libc_file = os.path.join(bionic_libc_root, stub) if not os.path.exists(libc_file): # new file, git add it - D("new file: " + stub) + logging.info("new file: " + stub) adds.append(libc_file) shutil.copyfile(tmp_file, libc_file) elif not filecmp.cmp(tmp_file, libc_file): - D("changed file: " + stub) + logging.info("changed file: " + stub) edits.append(stub) deletes = [] for stub in self.old_stubs: if not stub in self.new_stubs: - D("deleted file: " + stub) + logging.info("deleted file: " + stub) deletes.append(os.path.join(bionic_libc_root, stub)) if not DRY_RUN: @@ -539,11 +657,11 @@ class State: commands.getoutput("git add %s" % (os.path.join(bionic_libc_root, "SYSCALLS.TXT"))) if (not adds) and (not deletes) and (not edits): - D("no changes detected!") + logging.info("no changes detected!") else: - D("ready to go!!") + logging.info("ready to go!!") -D_setlevel(1) +logging.basicConfig(level=logging.INFO) state = State() state.process_file(os.path.join(bionic_libc_root, "SYSCALLS.TXT")) diff --git a/libc/upstream-freebsd/android/include/freebsd-compat.h b/libc/upstream-freebsd/android/include/freebsd-compat.h index d5f14258e..b44b94a8a 100644 --- a/libc/upstream-freebsd/android/include/freebsd-compat.h +++ b/libc/upstream-freebsd/android/include/freebsd-compat.h @@ -17,7 +17,7 @@ #ifndef _BIONIC_FREEBSD_COMPAT_H_included #define _BIONIC_FREEBSD_COMPAT_H_included -#define __USE_BSD +#define _BSD_SOURCE #define REPLACE_GETOPT /* diff --git a/libc/upstream-netbsd/android/include/namespace.h b/libc/upstream-netbsd/android/include/namespace.h index 5df543cfc..630ea9b06 100644 --- a/libc/upstream-netbsd/android/include/namespace.h +++ b/libc/upstream-netbsd/android/include/namespace.h @@ -17,11 +17,6 @@ #ifndef _BIONIC_NETBSD_NAMESPACE_H_included #define _BIONIC_NETBSD_NAMESPACE_H_included -// NetBSD uses __weak_alias on a lot of functions. We don't want that. -#if defined(__weak_alias) -#undef __weak_alias -#endif - __LIBC_HIDDEN__ int __res_enable_mt(void); __LIBC_HIDDEN__ int __res_disable_mt(void); diff --git a/libc/upstream-netbsd/android/include/netbsd-compat.h b/libc/upstream-netbsd/android/include/netbsd-compat.h index 84be93194..04bc728b5 100644 --- a/libc/upstream-netbsd/android/include/netbsd-compat.h +++ b/libc/upstream-netbsd/android/include/netbsd-compat.h @@ -17,6 +17,9 @@ #ifndef _BIONIC_NETBSD_COMPAT_H_included #define _BIONIC_NETBSD_COMPAT_H_included +#define _BSD_SOURCE +#define _GNU_SOURCE + // NetBSD uses _DIAGASSERT to null-check arguments and the like. #include <assert.h> #define _DIAGASSERT(e) ((e) ? (void) 0 : __assert2(__FILE__, __LINE__, __func__, #e)) @@ -24,9 +27,6 @@ // TODO: update our <sys/cdefs.h> to support this properly. #define __type_fit(t, a) (0 == 0) -#define _GNU_SOURCE -#define __USE_BSD - // TODO: we don't yet have thread-safe environment variables. #define __readlockenv() 0 #define __unlockenv() 0 diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h index 34ad2c5c8..630094d99 100644 --- a/libc/upstream-openbsd/android/include/openbsd-compat.h +++ b/libc/upstream-openbsd/android/include/openbsd-compat.h @@ -17,10 +17,23 @@ #ifndef _BIONIC_OPENBSD_COMPAT_H_included #define _BIONIC_OPENBSD_COMPAT_H_included +#define _BSD_SOURCE + #include <sys/cdefs.h> #include <stddef.h> // For size_t. -#define __USE_BSD +/* Redirect internal C library calls to the public function. */ +#define _err err +#define _errx errx +#define _verr verr +#define _verrx verrx +#define _vwarn vwarn +#define _vwarnx vwarnx +#define _warn warn +#define _warnx warnx + +/* Ignore all __weak_alias in OpenBSD. */ +#define __weak_alias(alias,sym) /* OpenBSD's <ctype.h> uses these names, which conflicted with stlport. * Additionally, we changed the numeric/digit type from N to D for libcxx. diff --git a/libc/upstream-openbsd/lib/libc/gen/daemon.c b/libc/upstream-openbsd/lib/libc/gen/daemon.c new file mode 100644 index 000000000..79f426473 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/gen/daemon.c @@ -0,0 +1,64 @@ +/* $OpenBSD: daemon.c,v 1.7 2010/07/27 22:29:09 marco Exp $ */ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#include <fcntl.h> +#include <paths.h> +#include <unistd.h> +#include <stdlib.h> + +int +daemon(int nochdir, int noclose) +{ + int fd; + + switch (fork()) { + case -1: + return (-1); + case 0: + break; + default: + _exit(0); + } + + if (setsid() == -1) + return (-1); + + if (!nochdir) + (void)chdir("/"); + + if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + (void)dup2(fd, STDIN_FILENO); + (void)dup2(fd, STDOUT_FILENO); + (void)dup2(fd, STDERR_FILENO); + if (fd > 2) + (void)close(fd); + } + return (0); +} diff --git a/libc/upstream-openbsd/lib/libc/gen/err.c b/libc/upstream-openbsd/lib/libc/gen/err.c new file mode 100644 index 000000000..e7ec29de4 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/gen/err.c @@ -0,0 +1,47 @@ +/* $OpenBSD: err.c,v 1.11 2012/12/05 23:19:59 deraadt Exp $ */ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#include <err.h> +#include <stdarg.h> + +/* PRINTFLIKE2 */ +__dead void +_err(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _verr(eval, fmt, ap); + va_end(ap); +} + +/* PRINTFLIKE2 */ +__weak_alias(err, _err); + diff --git a/libc/upstream-openbsd/lib/libc/gen/errx.c b/libc/upstream-openbsd/lib/libc/gen/errx.c new file mode 100644 index 000000000..d213435db --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/gen/errx.c @@ -0,0 +1,47 @@ +/* $OpenBSD: errx.c,v 1.10 2012/12/05 23:19:59 deraadt Exp $ */ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#include <err.h> +#include <stdarg.h> + +/* PRINTFLIKE2 */ +__dead void +_errx(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _verrx(eval, fmt, ap); + va_end(ap); +} + +/* PRINTFLIKE2 */ +__weak_alias(errx, _errx); + diff --git a/libc/bionic/err.c b/libc/upstream-openbsd/lib/libc/gen/verr.c index 84a3d85c3..dcd8edcd0 100644 --- a/libc/bionic/err.c +++ b/libc/upstream-openbsd/lib/libc/gen/verr.c @@ -1,6 +1,7 @@ +/* $OpenBSD: verr.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */ /*- * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,83 +28,17 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> #include <err.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <stdarg.h> -#include <errno.h> - -extern const char* __progname; - -__noreturn void -err(int eval, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - verr(eval, fmt, ap); - va_end(ap); -} - -__noreturn void -errx(int eval, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - verrx(eval, fmt, ap); - va_end(ap); -} - -__noreturn void -verr(int eval, const char *fmt, va_list ap) -{ - int sverrno; - - sverrno = errno; - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) { - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, ": "); - } - (void)fprintf(stderr, "%s\n", strerror(sverrno)); - exit(eval); -} +extern char *__progname; /* Program name, from crt0. */ -__noreturn void -verrx(int eval, const char *fmt, va_list ap) -{ - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, "\n"); - exit(eval); -} - -void -warn(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vwarn(fmt, ap); - va_end(ap); -} - -void -warnx(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vwarnx(fmt, ap); - va_end(ap); -} - -void -vwarn(const char *fmt, va_list ap) +__dead void +_verr(int eval, const char *fmt, va_list ap) { int sverrno; @@ -114,13 +49,8 @@ vwarn(const char *fmt, va_list ap) (void)fprintf(stderr, ": "); } (void)fprintf(stderr, "%s\n", strerror(sverrno)); + exit(eval); } -void -vwarnx(const char *fmt, va_list ap) -{ - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, "\n"); -} +__weak_alias(verr, _verr); + diff --git a/libc/upstream-openbsd/lib/libc/gen/verrx.c b/libc/upstream-openbsd/lib/libc/gen/verrx.c new file mode 100644 index 000000000..60da062f5 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/gen/verrx.c @@ -0,0 +1,49 @@ +/* $OpenBSD: verrx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +extern char *__progname; /* Program name, from crt0. */ + +__dead void +_verrx(int eval, const char *fmt, va_list ap) +{ + (void)fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "\n"); + exit(eval); +} + +__weak_alias(verrx, _verrx); + diff --git a/libc/upstream-openbsd/lib/libc/gen/vwarn.c b/libc/upstream-openbsd/lib/libc/gen/vwarn.c new file mode 100644 index 000000000..26b60f336 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/gen/vwarn.c @@ -0,0 +1,54 @@ +/* $OpenBSD: vwarn.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +extern char *__progname; /* Program name, from crt0. */ + +void +_vwarn(const char *fmt, va_list ap) +{ + int sverrno; + + sverrno = errno; + (void)fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) { + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, ": "); + } + (void)fprintf(stderr, "%s\n", strerror(sverrno)); +} + +__weak_alias(vwarn, _vwarn); + diff --git a/libc/upstream-openbsd/lib/libc/gen/vwarnx.c b/libc/upstream-openbsd/lib/libc/gen/vwarnx.c new file mode 100644 index 000000000..e6b1957d4 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/gen/vwarnx.c @@ -0,0 +1,47 @@ +/* $OpenBSD: vwarnx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#include <err.h> +#include <stdio.h> +#include <stdarg.h> + +extern char *__progname; /* Program name, from crt0. */ + +void +_vwarnx(const char *fmt, va_list ap) +{ + (void)fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "\n"); +} + +__weak_alias(vwarnx, _vwarnx); + diff --git a/libc/upstream-openbsd/lib/libc/gen/warn.c b/libc/upstream-openbsd/lib/libc/gen/warn.c new file mode 100644 index 000000000..c1b47a65f --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/gen/warn.c @@ -0,0 +1,47 @@ +/* $OpenBSD: warn.c,v 1.10 2012/12/05 23:20:00 deraadt Exp $ */ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#include <err.h> +#include <stdarg.h> + +/* PRINTFLIKE1 */ +void +_warn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _vwarn(fmt, ap); + va_end(ap); +} + +/* PRINTFLIKE1 */ +__weak_alias(warn, _warn); + diff --git a/libc/upstream-openbsd/lib/libc/gen/warnx.c b/libc/upstream-openbsd/lib/libc/gen/warnx.c new file mode 100644 index 000000000..af2ab669c --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/gen/warnx.c @@ -0,0 +1,47 @@ +/* $OpenBSD: warnx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#include <err.h> +#include <stdarg.h> + +/* PRINTFLIKE1 */ +void +_warnx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _vwarnx(fmt, ap); + va_end(ap); +} + +/* PRINTFLIKE1 */ +__weak_alias(warnx, _warnx); + diff --git a/libc/upstream-openbsd/lib/libc/net/res_random.c b/libc/upstream-openbsd/lib/libc/net/res_random.c new file mode 100644 index 000000000..f28692f7c --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/net/res_random.c @@ -0,0 +1,275 @@ +/* $OpenBSD: res_random.c,v 1.21 2014/07/20 04:22:34 guenther Exp $ */ + +/* + * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> + * Copyright 2008 Damien Miller <djm@openbsd.org> + * All rights reserved. + * + * Theo de Raadt <deraadt@openbsd.org> came up with the idea of using + * such a mathematical system to generate more random (yet non-repeating) + * ids to solve the resolver/named problem. But Niels designed the + * actual system based on the constraints. + * + * Later modified by Damien Miller to wrap the LCG output in a 15-bit + * permutation generator based on a Luby-Rackoff block cipher. This + * ensures the output is non-repeating and preserves the MSB twiddle + * trick, but makes it more resistant to LCG prediction. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * seed = random 15bit + * n = prime, g0 = generator to n, + * j = random so that gcd(j,n-1) == 1 + * g = g0^j mod n will be a generator again. + * + * X[0] = random seed. + * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator + * with a = 7^(even random) mod m, + * b = random with gcd(b,m) == 1 + * m = 31104 and a maximal period of m-1. + * + * The transaction id is determined by: + * id[n] = seed xor (g^X[n] mod n) + * + * Effectivly the id is restricted to the lower 15 bits, thus + * yielding two different cycles by toggling the msb on and off. + * This avoids reuse issues caused by reseeding. + * + * The output of this generator is then randomly permuted though a + * custom 15 bit Luby-Rackoff block cipher. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/time.h> +#include <resolv.h> + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include "thread_private.h" + +#define RU_OUT 180 /* Time after wich will be reseeded */ +#define RU_MAX 30000 /* Uniq cycle, avoid blackjack prediction */ +#define RU_GEN 2 /* Starting generator */ +#define RU_N 32749 /* RU_N-1 = 2*2*3*2729 */ +#define RU_AGEN 7 /* determine ru_a as RU_AGEN^(2*rand) */ +#define RU_M 31104 /* RU_M = 2^7*3^5 - don't change */ +#define RU_ROUNDS 11 /* Number of rounds for permute (odd) */ + +struct prf_ctx { + /* PRF lookup table for odd rounds (7 bits input to 8 bits output) */ + u_char prf7[(RU_ROUNDS / 2) * (1 << 7)]; + + /* PRF lookup table for even rounds (8 bits input to 7 bits output) */ + u_char prf8[((RU_ROUNDS + 1) / 2) * (1 << 8)]; +}; + +#define PFAC_N 3 +static const u_int16_t pfacts[PFAC_N] = { + 2, + 3, + 2729 +}; + +static u_int16_t ru_x; +static u_int16_t ru_seed, ru_seed2; +static u_int16_t ru_a, ru_b; +static u_int16_t ru_g; +static u_int16_t ru_counter = 0; +static u_int16_t ru_msb = 0; +static struct prf_ctx *ru_prf = NULL; +static time_t ru_reseed; + +static u_int16_t pmod(u_int16_t, u_int16_t, u_int16_t); +static void res_initid(void); + +/* + * Do a fast modular exponation, returned value will be in the range + * of 0 - (mod-1) + */ +static u_int16_t +pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod) +{ + u_int16_t s, t, u; + + s = 1; + t = gen; + u = exp; + + while (u) { + if (u & 1) + s = (s * t) % mod; + u >>= 1; + t = (t * t) % mod; + } + return (s); +} + +/* + * 15-bit permutation based on Luby-Rackoff block cipher + */ +static u_int +permute15(u_int in) +{ + int i; + u_int left, right, tmp; + + if (ru_prf == NULL) + return in; + + left = (in >> 8) & 0x7f; + right = in & 0xff; + + /* + * Each round swaps the width of left and right. Even rounds have + * a 7-bit left, odd rounds have an 8-bit left. Since this uses an + * odd number of rounds, left is always 8 bits wide at the end. + */ + for (i = 0; i < RU_ROUNDS; i++) { + if ((i & 1) == 0) + tmp = ru_prf->prf8[(i << (8 - 1)) | right] & 0x7f; + else + tmp = ru_prf->prf7[((i - 1) << (7 - 1)) | right]; + tmp ^= left; + left = right; + right = tmp; + } + + return (right << 8) | left; +} + +/* + * Initializes the seed and chooses a suitable generator. Also toggles + * the msb flag. The msb flag is used to generate two distinct + * cycles of random numbers and thus avoiding reuse of ids. + * + * This function is called from res_randomid() when needed, an + * application does not have to worry about it. + */ +static void +res_initid(void) +{ + u_int16_t j, i; + u_int32_t tmp; + int noprime = 1; + struct timespec ts; + + ru_x = arc4random_uniform(RU_M); + + /* 15 bits of random seed */ + tmp = arc4random(); + ru_seed = (tmp >> 16) & 0x7FFF; + ru_seed2 = tmp & 0x7FFF; + + /* Determine the LCG we use */ + tmp = arc4random(); + ru_b = (tmp & 0xfffe) | 1; + ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M); + while (ru_b % 3 == 0) + ru_b += 2; + + j = arc4random_uniform(RU_N); + + /* + * Do a fast gcd(j,RU_N-1), so we can find a j with + * gcd(j, RU_N-1) == 1, giving a new generator for + * RU_GEN^j mod RU_N + */ + + while (noprime) { + for (i = 0; i < PFAC_N; i++) + if (j % pfacts[i] == 0) + break; + + if (i >= PFAC_N) + noprime = 0; + else + j = (j + 1) % RU_N; + } + + ru_g = pmod(RU_GEN, j, RU_N); + ru_counter = 0; + + /* Initialise PRF for Luby-Rackoff permutation */ + if (ru_prf == NULL) + ru_prf = malloc(sizeof(*ru_prf)); + if (ru_prf != NULL) + arc4random_buf(ru_prf, sizeof(*ru_prf)); + + clock_gettime(CLOCK_MONOTONIC, &ts); + ru_reseed = ts.tv_sec + RU_OUT; + ru_msb = ru_msb == 0x8000 ? 0 : 0x8000; +} + +u_int +res_randomid(void) +{ + struct timespec ts; + u_int r; + _THREAD_PRIVATE_MUTEX(random); + + clock_gettime(CLOCK_MONOTONIC, &ts); + + _THREAD_PRIVATE_MUTEX_LOCK(random); + + if (ru_counter >= RU_MAX || ts.tv_sec > ru_reseed) + res_initid(); + + /* Linear Congruential Generator */ + ru_x = (ru_a * ru_x + ru_b) % RU_M; + ru_counter++; + + r = permute15(ru_seed ^ pmod(ru_g, ru_seed2 + ru_x, RU_N)) | ru_msb; + + _THREAD_PRIVATE_MUTEX_UNLOCK(random); + + return (r); +} + +#if 0 +int +main(int argc, char **argv) +{ + int i, n; + u_int16_t wert; + + res_initid(); + + printf("Generator: %u\n", ru_g); + printf("Seed: %u\n", ru_seed); + printf("Reseed at %ld\n", ru_reseed); + printf("Ru_X: %u\n", ru_x); + printf("Ru_A: %u\n", ru_a); + printf("Ru_B: %u\n", ru_b); + + n = argc > 1 ? atoi(argv[1]) : 60001; + for (i=0;i<n;i++) { + wert = res_randomid(); + printf("%u\n", wert); + } + return 0; +} +#endif + diff --git a/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c b/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c new file mode 100644 index 000000000..8cda04763 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c @@ -0,0 +1,183 @@ +/* $OpenBSD: fmemopen.c,v 1.2 2013/03/27 15:06:25 mpi Exp $ */ + +/* + * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org> + * Copyright (c) 2009 Ted Unangst + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "local.h" + +struct state { + char *string; /* actual stream */ + size_t pos; /* current position */ + size_t size; /* allocated size */ + size_t len; /* length of the data */ + int update; /* open for update */ +}; + +static int +fmemopen_read(void *v, char *b, int l) +{ + struct state *st = v; + int i; + + for (i = 0; i < l && i + st->pos < st->len; i++) + b[i] = st->string[st->pos + i]; + st->pos += i; + + return (i); +} + +static int +fmemopen_write(void *v, const char *b, int l) +{ + struct state *st = v; + int i; + + for (i = 0; i < l && i + st->pos < st->size; i++) + st->string[st->pos + i] = b[i]; + st->pos += i; + + if (st->pos >= st->len) { + st->len = st->pos; + + if (st->len < st->size) + st->string[st->len] = '\0'; + else if (!st->update) + st->string[st->size - 1] = '\0'; + } + + return (i); +} + +static fpos_t +fmemopen_seek(void *v, fpos_t off, int whence) +{ + struct state *st = v; + ssize_t base = 0; + + switch (whence) { + case SEEK_SET: + break; + case SEEK_CUR: + base = st->pos; + break; + case SEEK_END: + base = st->len; + break; + } + + if (off > st->size - base || off < -base) { + errno = EOVERFLOW; + return (-1); + } + + st->pos = base + off; + + return (st->pos); +} + +static int +fmemopen_close(void *v) +{ + free(v); + + return (0); +} + +static int +fmemopen_close_free(void *v) +{ + struct state *st = v; + + free(st->string); + free(st); + + return (0); +} + +FILE * +fmemopen(void *buf, size_t size, const char *mode) +{ + struct state *st; + FILE *fp; + int flags, oflags; + + if (size == 0) { + errno = EINVAL; + return (NULL); + } + + if ((flags = __sflags(mode, &oflags)) == 0) { + errno = EINVAL; + return (NULL); + } + + if (buf == NULL && ((oflags & O_RDWR) == 0)) { + errno = EINVAL; + return (NULL); + } + + if ((st = malloc(sizeof(*st))) == NULL) + return (NULL); + + if ((fp = __sfp()) == NULL) { + free(st); + return (NULL); + } + + st->pos = 0; + st->len = (oflags & O_WRONLY) ? 0 : size; + st->size = size; + st->update = oflags & O_RDWR; + + if (buf == NULL) { + if ((st->string = malloc(size)) == NULL) { + free(st); + fp->_flags = 0; + return (NULL); + } + *st->string = '\0'; + } else { + st->string = (char *)buf; + + if (oflags & O_TRUNC) + *st->string = '\0'; + + if (oflags & O_APPEND) { + char *p; + + if ((p = memchr(st->string, '\0', size)) != NULL) + st->pos = st->len = (p - st->string); + else + st->pos = st->len = size; + } + } + + fp->_flags = (short)flags; + fp->_file = -1; + fp->_cookie = (void *)st; + fp->_read = (flags & __SWR) ? NULL : fmemopen_read; + fp->_write = (flags & __SRD) ? NULL : fmemopen_write; + fp->_seek = fmemopen_seek; + fp->_close = (buf == NULL) ? fmemopen_close_free : fmemopen_close; + + return (fp); +} diff --git a/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c b/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c new file mode 100644 index 000000000..46105358d --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c @@ -0,0 +1,158 @@ +/* $OpenBSD: open_memstream.c,v 1.3 2013/04/03 03:11:53 guenther Exp $ */ + +/* + * Copyright (c) 2011 Martin Pieuchot <mpi@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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "local.h" + +struct state { + char *string; /* actual stream */ + char **pbuf; /* point to the stream */ + size_t *psize; /* point to min(pos, len) */ + size_t pos; /* current position */ + size_t size; /* number of allocated char */ + size_t len; /* length of the data */ +}; + +static int +memstream_write(void *v, const char *b, int l) +{ + struct state *st = v; + char *p; + size_t i, end; + + end = (st->pos + l); + + if (end >= st->size) { + /* 1.6 is (very) close to the golden ratio. */ + size_t sz = st->size * 8 / 5; + + if (sz < end + 1) + sz = end + 1; + p = realloc(st->string, sz); + if (!p) + return (-1); + bzero(p + st->size, sz - st->size); + *st->pbuf = st->string = p; + st->size = sz; + } + + for (i = 0; i < l; i++) + st->string[st->pos + i] = b[i]; + st->pos += l; + + if (st->pos > st->len) { + st->len = st->pos; + st->string[st->len] = '\0'; + } + + *st->psize = st->pos; + + return (i); +} + +static fpos_t +memstream_seek(void *v, fpos_t off, int whence) +{ + struct state *st = v; + ssize_t base = 0; + + switch (whence) { + case SEEK_SET: + break; + case SEEK_CUR: + base = st->pos; + break; + case SEEK_END: + base = st->len; + break; + } + + if (off > SIZE_MAX - base || off < -base) { + errno = EOVERFLOW; + return (-1); + } + + st->pos = base + off; + *st->psize = MIN(st->pos, st->len); + + return (st->pos); +} + +static int +memstream_close(void *v) +{ + struct state *st = v; + + free(st); + + return (0); +} + +FILE * +open_memstream(char **pbuf, size_t *psize) +{ + struct state *st; + FILE *fp; + + if (pbuf == NULL || psize == NULL) { + errno = EINVAL; + return (NULL); + } + + if ((st = malloc(sizeof(*st))) == NULL) + return (NULL); + + if ((fp = __sfp()) == NULL) { + free(st); + return (NULL); + } + + st->size = BUFSIZ; + if ((st->string = calloc(1, st->size)) == NULL) { + free(st); + fp->_flags = 0; + return (NULL); + } + + *st->string = '\0'; + st->pos = 0; + st->len = 0; + st->pbuf = pbuf; + st->psize = psize; + + *pbuf = st->string; + *psize = st->len; + + fp->_flags = __SWR; + fp->_file = -1; + fp->_cookie = st; + fp->_read = NULL; + fp->_write = memstream_write; + fp->_seek = memstream_seek; + fp->_close = memstream_close; + _SET_ORIENTATION(fp, -1); + + return (fp); +} diff --git a/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c b/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c new file mode 100644 index 000000000..94141878f --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c @@ -0,0 +1,169 @@ +/* $OpenBSD: open_wmemstream.c,v 1.3 2014/03/06 07:28:21 gerhard Exp $ */ + +/* + * Copyright (c) 2011 Martin Pieuchot <mpi@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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include "local.h" + +struct state { + wchar_t *string; /* actual stream */ + wchar_t **pbuf; /* point to the stream */ + size_t *psize; /* point to min(pos, len) */ + size_t pos; /* current position */ + size_t size; /* number of allocated wchar_t */ + size_t len; /* length of the data */ + mbstate_t mbs; /* conversion state of the stream */ +}; + +static int +wmemstream_write(void *v, const char *b, int l) +{ + struct state *st = v; + wchar_t *p; + size_t nmc, len, end; + + end = (st->pos + l); + + if (end >= st->size) { + /* 1.6 is (very) close to the golden ratio. */ + size_t sz = st->size * 8 / 5; + + if (sz < end + 1) + sz = end + 1; + p = realloc(st->string, sz * sizeof(wchar_t)); + if (!p) + return (-1); + bzero(p + st->size, (sz - st->size) * sizeof(wchar_t)); + *st->pbuf = st->string = p; + st->size = sz; + } + + nmc = (st->size - st->pos) * sizeof(wchar_t); + len = mbsnrtowcs(st->string + st->pos, &b, nmc, l, &st->mbs); + if (len == (size_t)-1) + return (-1); + st->pos += len; + + if (st->pos > st->len) { + st->len = st->pos; + st->string[st->len] = L'\0'; + } + + *st->psize = st->pos; + + return (len); +} + +static fpos_t +wmemstream_seek(void *v, fpos_t off, int whence) +{ + struct state *st = v; + ssize_t base = 0; + + switch (whence) { + case SEEK_SET: + break; + case SEEK_CUR: + base = st->pos; + break; + case SEEK_END: + base = st->len; + break; + } + + if (off > (SIZE_MAX / sizeof(wchar_t)) - base || off < -base) { + errno = EOVERFLOW; + return (-1); + } + + /* + * XXX Clearing mbs here invalidates shift state for state- + * dependent encodings, but they are not (yet) supported. + */ + bzero(&st->mbs, sizeof(st->mbs)); + + st->pos = base + off; + *st->psize = MIN(st->pos, st->len); + + return (st->pos); +} + +static int +wmemstream_close(void *v) +{ + struct state *st = v; + + free(st); + + return (0); +} + +FILE * +open_wmemstream(wchar_t **pbuf, size_t *psize) +{ + struct state *st; + FILE *fp; + + if (pbuf == NULL || psize == NULL) { + errno = EINVAL; + return (NULL); + } + + if ((st = malloc(sizeof(*st))) == NULL) + return (NULL); + + if ((fp = __sfp()) == NULL) { + free(st); + return (NULL); + } + + st->size = BUFSIZ * sizeof(wchar_t); + if ((st->string = calloc(1, st->size)) == NULL) { + free(st); + fp->_flags = 0; + return (NULL); + } + + *st->string = L'\0'; + st->pos = 0; + st->len = 0; + st->pbuf = pbuf; + st->psize = psize; + bzero(&st->mbs, sizeof(st->mbs)); + + *pbuf = st->string; + *psize = st->len; + + fp->_flags = __SWR; + fp->_file = -1; + fp->_cookie = st; + fp->_read = NULL; + fp->_write = wmemstream_write; + fp->_seek = wmemstream_seek; + fp->_close = wmemstream_close; + _SET_ORIENTATION(fp, 1); + + return (fp); +} diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata Binary files differindex 9547f584c..8d574f561 100644 --- a/libc/zoneinfo/tzdata +++ b/libc/zoneinfo/tzdata diff --git a/libm/include/math.h b/libm/include/math.h index 4faec333f..1fcc578dc 100644 --- a/libm/include/math.h +++ b/libm/include/math.h @@ -36,11 +36,11 @@ extern const union __nan_un { float __uf; } __nan; -#if __GNUC_PREREQ__(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800) +#if __GNUC_PREREQ(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800) #define __MATH_BUILTIN_CONSTANTS #endif -#if __GNUC_PREREQ__(3, 0) && !defined(__INTEL_COMPILER) +#if __GNUC_PREREQ(3, 0) && !defined(__INTEL_COMPILER) #define __MATH_BUILTIN_RELOPS #endif @@ -462,11 +462,11 @@ long double truncl(long double); #endif /* __ISO_C_VISIBLE >= 1999 */ -#if defined(_GNU_SOURCE) +#if defined(__USE_GNU) void sincos(double, double*, double*); void sincosf(float, float*, float*); void sincosl(long double, long double*, long double*); -#endif /* _GNU_SOURCE */ +#endif /* __USE_GNU */ #pragma GCC visibility pop __END_DECLS diff --git a/libm/sincos.c b/libm/sincos.c index ad755490f..a5608cfed 100644 --- a/libm/sincos.c +++ b/libm/sincos.c @@ -22,8 +22,8 @@ * 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. - * */ + #define _GNU_SOURCE 1 #include <math.h> diff --git a/libstdc++/Android.mk b/libstdc++/Android.mk deleted file mode 100644 index ff9609aca..000000000 --- a/libstdc++/Android.mk +++ /dev/null @@ -1,15 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := src/libstdc++.cpp -LOCAL_MODULE:= libstdc++ -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_SYSTEM_SHARED_LIBRARIES := libc -include $(BUILD_SHARED_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES:= src/libstdc++.cpp -LOCAL_MODULE:= libstdc++ -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_SYSTEM_SHARED_LIBRARIES := libc -include $(BUILD_STATIC_LIBRARY) diff --git a/libstdc++/include/new b/libstdc++/include/new index 0253e8b68..c5a43de43 100644 --- a/libstdc++/include/new +++ b/libstdc++/include/new @@ -13,19 +13,19 @@ namespace std { void* operator new(std::size_t); void* operator new[](std::size_t); -void operator delete(void*); -void operator delete[](void*); +void operator delete(void*) throw(); +void operator delete[](void*) throw(); void* operator new(std::size_t, const std::nothrow_t&); void* operator new[](std::size_t, const std::nothrow_t&); -void operator delete(void*, const std::nothrow_t&); -void operator delete[](void*, const std::nothrow_t&); +void operator delete(void*, const std::nothrow_t&) throw(); +void operator delete[](void*, const std::nothrow_t&) throw(); inline void* operator new(std::size_t, void* p) { return p; } inline void* operator new[](std::size_t, void* p) { return p; } // these next two are not really required, since exceptions are off -inline void operator delete(void*, void*) { } -inline void operator delete[](void*, void*) { } +inline void operator delete(void*, void*) throw() { } +inline void operator delete[](void*, void*) throw() { } } // extern C++ diff --git a/libstdc++/src/libstdc++.cpp b/libstdc++/src/libstdc++.cpp deleted file mode 100644 index 3676aa19f..000000000 --- a/libstdc++/src/libstdc++.cpp +++ /dev/null @@ -1 +0,0 @@ -extern "C" void __this_library_is_now_part_of_libc() {} diff --git a/linker/Android.mk b/linker/Android.mk index 68e801da2..4298032a4 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -8,6 +8,7 @@ LOCAL_SRC_FILES:= \ linker.cpp \ linker_allocator.cpp \ linker_environ.cpp \ + linker_libc_support.c \ linker_phdr.cpp \ rt.cpp \ @@ -57,6 +58,10 @@ LOCAL_MODULE_STEM_32 := linker LOCAL_MODULE_STEM_64 := linker64 LOCAL_MULTILIB := both +# Leave the symbols in the shared library so that stack unwinders can produce +# meaningful name resolution. +LOCAL_STRIP_MODULE := keep_symbols + include $(LOCAL_PATH)/linker_executable.mk ifdef TARGET_2ND_ARCH LOCAL_2ND_ARCH_VAR_PREFIX := $(TARGET_2ND_ARCH_VAR_PREFIX) diff --git a/linker/debugger.cpp b/linker/debugger.cpp index 079682cab..6565985b5 100644 --- a/linker/debugger.cpp +++ b/linker/debugger.cpp @@ -162,17 +162,17 @@ static void log_signal_summary(int signum, const siginfo_t* info) { thread_name[MAX_TASK_NAME_LEN] = 0; } - // "info" will be NULL if the siginfo_t information was not available. + // "info" will be null if the siginfo_t information was not available. // Many signals don't have an address or a code. char code_desc[32]; // ", code -6" char addr_desc[32]; // ", fault addr 0x1234" addr_desc[0] = code_desc[0] = 0; - if (info != NULL) { + if (info != nullptr) { // For a rethrown signal, this si_code will be right and the one debuggerd shows will // always be SI_TKILL. - snprintf(code_desc, sizeof(code_desc), ", code %d", info->si_code); + __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code); if (has_address) { - snprintf(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr); + __libc_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr); } } __libc_format_log(ANDROID_LOG_FATAL, "libc", @@ -198,7 +198,7 @@ static bool have_siginfo(int signum) { } bool result = (old_action.sa_flags & SA_SIGINFO) != 0; - if (sigaction(signum, &old_action, NULL) == -1) { + if (sigaction(signum, &old_action, nullptr) == -1) { __libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s", strerror(errno)); } @@ -230,7 +230,7 @@ static void send_debuggerd_packet(siginfo_t* info) { msg.action = DEBUGGER_ACTION_CRASH; msg.tid = gettid(); msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_abort_message); - msg.original_si_code = (info != NULL) ? info->si_code : 0; + msg.original_si_code = (info != nullptr) ? info->si_code : 0; int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))); if (ret == sizeof(msg)) { char debuggerd_ack; @@ -255,7 +255,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) // It's possible somebody cleared the SA_SIGINFO flag, which would mean // our "info" arg holds an undefined value. if (!have_siginfo(signal_number)) { - info = NULL; + info = nullptr; } log_signal_summary(signal_number, info); @@ -296,14 +296,14 @@ __LIBC_HIDDEN__ void debuggerd_init() { // Use the alternate signal stack if available so we can catch stack overflows. action.sa_flags |= SA_ONSTACK; - sigaction(SIGABRT, &action, NULL); - sigaction(SIGBUS, &action, NULL); - sigaction(SIGFPE, &action, NULL); - sigaction(SIGILL, &action, NULL); - sigaction(SIGPIPE, &action, NULL); - sigaction(SIGSEGV, &action, NULL); + sigaction(SIGABRT, &action, nullptr); + sigaction(SIGBUS, &action, nullptr); + sigaction(SIGFPE, &action, nullptr); + sigaction(SIGILL, &action, nullptr); + sigaction(SIGPIPE, &action, nullptr); + sigaction(SIGSEGV, &action, nullptr); #if defined(SIGSTKFLT) - sigaction(SIGSTKFLT, &action, NULL); + sigaction(SIGSTKFLT, &action, nullptr); #endif - sigaction(SIGTRAP, &action, NULL); + sigaction(SIGTRAP, &action, nullptr); } diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 8ebf3576b..38484d995 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -42,7 +42,7 @@ static const char* __bionic_set_dlerror(char* new_value) { static void __bionic_format_dlerror(const char* msg, const char* detail) { char* buffer = __get_thread()->dlerror_buffer; strlcpy(buffer, msg, __BIONIC_DLERROR_BUFFER_SIZE); - if (detail != NULL) { + if (detail != nullptr) { strlcat(buffer, ": ", __BIONIC_DLERROR_BUFFER_SIZE); strlcat(buffer, detail, __BIONIC_DLERROR_BUFFER_SIZE); } @@ -51,7 +51,7 @@ static void __bionic_format_dlerror(const char* msg, const char* detail) { } const char* dlerror() { - const char* old_value = __bionic_set_dlerror(NULL); + const char* old_value = __bionic_set_dlerror(nullptr); return old_value; } @@ -68,9 +68,9 @@ void android_update_LD_LIBRARY_PATH(const char* ld_library_path) { static void* dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) { ScopedPthreadMutexLocker locker(&g_dl_mutex); soinfo* result = do_dlopen(filename, flags, extinfo); - if (result == NULL) { + if (result == nullptr) { __bionic_format_dlerror("dlopen failed", linker_get_error_buffer()); - return NULL; + return nullptr; } return result; } @@ -80,45 +80,52 @@ void* android_dlopen_ext(const char* filename, int flags, const android_dlextinf } void* dlopen(const char* filename, int flags) { - return dlopen_ext(filename, flags, NULL); + return dlopen_ext(filename, flags, nullptr); } void* dlsym(void* handle, const char* symbol) { ScopedPthreadMutexLocker locker(&g_dl_mutex); #if !defined(__LP64__) - if (handle == NULL) { - __bionic_format_dlerror("dlsym library handle is null", NULL); - return NULL; + if (handle == nullptr) { + __bionic_format_dlerror("dlsym library handle is null", nullptr); + return nullptr; } #endif - if (symbol == NULL) { - __bionic_format_dlerror("dlsym symbol name is null", NULL); - return NULL; + if (symbol == nullptr) { + __bionic_format_dlerror("dlsym symbol name is null", nullptr); + return nullptr; } - soinfo* found = NULL; - ElfW(Sym)* sym = NULL; - void* caller_addr = __builtin_return_address(0); - soinfo* caller_si = find_containing_library(caller_addr); - + soinfo* found = nullptr; + ElfW(Sym)* sym = nullptr; if (handle == RTLD_DEFAULT) { - sym = dlsym_linear_lookup(symbol, &found, NULL, caller_si); + sym = dlsym_linear_lookup(symbol, &found, nullptr); } else if (handle == RTLD_NEXT) { - sym = NULL; - if (caller_si && caller_si->next) { - sym = dlsym_linear_lookup(symbol, &found, caller_si->next, caller_si); + void* caller_addr = __builtin_return_address(0); + soinfo* si = find_containing_library(caller_addr); + + sym = nullptr; + if (si && si->next) { + sym = dlsym_linear_lookup(symbol, &found, si->next); } } else { - sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol, caller_si); + sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol); } - if (sym != NULL && sym->st_shndx != 0) { - return reinterpret_cast<void*>(sym->st_value + found->load_bias); + if (sym != nullptr) { + 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 nullptr; } else { __bionic_format_dlerror("undefined symbol", symbol); - return NULL; + return nullptr; } } @@ -127,7 +134,7 @@ int dladdr(const void* addr, Dl_info* info) { // Determine if this address can be found in any library currently mapped. soinfo* si = find_containing_library(addr); - if (si == NULL) { + if (si == nullptr) { return 0; } @@ -139,7 +146,7 @@ int dladdr(const void* addr, Dl_info* info) { // Determine if any symbol in the library contains the specified address. ElfW(Sym)* sym = dladdr_find_symbol(si, addr); - if (sym != NULL) { + if (sym != nullptr) { info->dli_sname = si->strtab + sym->st_name; info->dli_saddr = reinterpret_cast<void*>(si->load_bias + sym->st_value); } @@ -157,7 +164,7 @@ int dlclose(void* handle) { // name_offset: starting index of the name in libdl_info.strtab #define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \ { name_offset, \ - reinterpret_cast<Elf32_Addr>(reinterpret_cast<void*>(value)), \ + reinterpret_cast<Elf32_Addr>(value), \ /* st_size */ 0, \ (shndx == 0) ? 0 : (STB_GLOBAL << 4), \ /* st_other */ 0, \ @@ -169,7 +176,7 @@ int dlclose(void* handle) { (shndx == 0) ? 0 : (STB_GLOBAL << 4), \ /* st_other */ 0, \ shndx, \ - reinterpret_cast<Elf64_Addr>(reinterpret_cast<void*>(value)), \ + reinterpret_cast<Elf64_Addr>(value), \ /* st_size */ 0, \ } @@ -192,7 +199,7 @@ static ElfW(Sym) g_libdl_symtab[] = { // This is actually the STH_UNDEF entry. Technically, it's // supposed to have st_name == 0, but instead, it points to an index // in the strtab with a \0 to make iterating through the symtab easier. - ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, NULL, 0), + ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, nullptr, 0), ELFW(SYM_INITIALIZER)( 0, &dlopen, 1), ELFW(SYM_INITIALIZER)( 7, &dlclose, 1), ELFW(SYM_INITIALIZER)( 15, &dlsym, 1), @@ -225,17 +232,12 @@ static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 }; static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; #endif -// Defined as global because we do not yet have access -// to synchronization functions __cxa_guard_* needed -// to define statics inside functions. -static soinfo __libdl_info; +static soinfo __libdl_info("libdl.so", nullptr); // This is used by the dynamic linker. Every process gets these symbols for free. soinfo* get_libdl_info() { - if (__libdl_info.name[0] == '\0') { - // initialize - strncpy(__libdl_info.name, "libdl.so", sizeof(__libdl_info.name)); - __libdl_info.flags = FLAG_LINKED | FLAG_NEW_SOINFO; + if ((__libdl_info.flags & FLAG_LINKED) == 0) { + __libdl_info.flags |= FLAG_LINKED; __libdl_info.strtab = ANDROID_LIBDL_STRTAB; __libdl_info.symtab = g_libdl_symtab; __libdl_info.nbucket = sizeof(g_libdl_buckets)/sizeof(unsigned); diff --git a/linker/linked_list.h b/linker/linked_list.h index 8096e623d..5fbdc8ffb 100644 --- a/linker/linked_list.h +++ b/linker/linked_list.h @@ -32,6 +32,9 @@ template<typename T, typename Allocator> class LinkedList { public: LinkedList() : head_(nullptr), tail_(nullptr) {} + ~LinkedList() { + clear(); + } void push_front(T* const element) { LinkedListEntry<T>* new_entry = Allocator::alloc(); @@ -83,26 +86,63 @@ class LinkedList { } template<typename F> - void for_each(F&& action) { + void for_each(F action) { + visit([&] (T* si) { + action(si); + return true; + }); + } + + template<typename F> + bool visit(F action) { for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) { - if (e->element != nullptr) { - action(e->element); + if (!action(e->element)) { + return false; } } + return true; } template<typename F> - void remove_if(F&& predicate) { - for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) { - if (e->element != nullptr && predicate(e->element)) { - e->element = nullptr; + void remove_if(F predicate) { + for (LinkedListEntry<T>* e = head_, *p = nullptr; e != nullptr;) { + if (predicate(e->element)) { + LinkedListEntry<T>* next = e->next; + if (p == nullptr) { + head_ = next; + } else { + p->next = next; + } + Allocator::free(e); + e = next; + } else { + p = e; + e = e->next; } } } - bool contains(const T* el) { + size_t size() const { + size_t sz = 0; + for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) { + ++sz; + } + + return sz; + } + + size_t copy_to_array(T* array[], size_t array_length) const { + size_t sz = 0; + for (LinkedListEntry<T>* e = head_; sz < array_length && e != nullptr; e = e->next) { + array[sz++] = e->element; + } + + return sz; + } + + bool contains(const T* el) const { for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) { - if (e->element != nullptr && e->element == el) { + if (e->element == el) { return true; } } diff --git a/linker/linker.cpp b/linker/linker.cpp index 9ab4e6108..9eb74403c 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -35,9 +35,10 @@ #include <stdlib.h> #include <string.h> #include <sys/mman.h> -#include <sys/stat.h> #include <unistd.h> +#include <new> + // Private C library headers. #include "private/bionic_tls.h" #include "private/KernelArgumentBlock.h" @@ -78,7 +79,6 @@ static const char* get_base_name(const char* name) { #define SEARCH_NAME(x) get_base_name(x) #endif -static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo); static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf); static LinkerAllocator<soinfo> g_soinfo_allocator; @@ -96,7 +96,7 @@ static const char* const kDefaultLdPaths[] = { "/vendor/lib", "/system/lib", #endif - NULL + nullptr }; #define LDPATH_BUFSIZE (LDPATH_MAX*64) @@ -115,7 +115,7 @@ static soinfo* g_ld_preloads[LDPRELOAD_MAX + 1]; __LIBC_HIDDEN__ int g_ld_debug_verbosity; -__LIBC_HIDDEN__ abort_msg_t* g_abort_message = NULL; // For debuggerd. +__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd. enum RelocationKind { kRelocAbsolute = 0, @@ -125,11 +125,6 @@ enum RelocationKind { kRelocMax }; -enum class SymbolLookupScope { - kAllowLocal, - kExcludeLocal, -}; - #if STATS struct linker_stats_t { int count[kRelocMax]; @@ -193,7 +188,7 @@ size_t linker_get_error_buffer_size() { extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity(); static pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER; -static r_debug _r_debug = {1, NULL, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0}; +static r_debug _r_debug = {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0}; static link_map* r_debug_tail = 0; static void insert_soinfo_into_debug_map(soinfo* info) { @@ -292,20 +287,10 @@ static void protect_data(int protection) { static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) { if (strlen(name) >= SOINFO_NAME_LEN) { DL_ERR("library name \"%s\" too long", name); - return NULL; + return nullptr; } - soinfo* si = g_soinfo_allocator.alloc(); - - // Initialize the new element. - memset(si, 0, sizeof(soinfo)); - strlcpy(si->name, name, sizeof(si->name)); - si->flags = FLAG_NEW_SOINFO; - - if (file_stat != NULL) { - si->set_st_dev(file_stat->st_dev); - si->set_st_ino(file_stat->st_ino); - } + soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat); sonext->next = si; sonext = si; @@ -315,7 +300,7 @@ static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) { } static void soinfo_free(soinfo* si) { - if (si == NULL) { + if (si == nullptr) { return; } @@ -323,16 +308,16 @@ static void soinfo_free(soinfo* si) { munmap(reinterpret_cast<void*>(si->base), si->size); } - soinfo *prev = NULL, *trav; + soinfo *prev = nullptr, *trav; TRACE("name %s: freeing soinfo @ %p", si->name, si); - for (trav = solist; trav != NULL; trav = trav->next) { + for (trav = solist; trav != nullptr; trav = trav->next) { if (trav == si) break; prev = trav; } - if (trav == NULL) { + if (trav == nullptr) { /* si was not in solist */ DL_ERR("name \"%s\" is not in solist!", si->name); return; @@ -341,7 +326,7 @@ static void soinfo_free(soinfo* si) { // clear links to/from si si->remove_all_links(); - /* prev will never be NULL, because the first entry in solist is + /* prev will never be null, because the first entry in solist is always the static libdl_info. */ prev->next = si->next; @@ -355,7 +340,7 @@ static void soinfo_free(soinfo* si) { static void parse_path(const char* path, const char* delimiters, const char** array, char* buf, size_t buf_size, size_t max_count) { - if (path == NULL) { + if (path == nullptr) { return; } @@ -372,9 +357,9 @@ static void parse_path(const char* path, const char* delimiters, // Forget the last path if we had to truncate; this occurs if the 2nd to // last char isn't '\0' (i.e. wasn't originally a delimiter). if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') { - array[i - 1] = NULL; + array[i - 1] = nullptr; } else { - array[i] = NULL; + array[i] = nullptr; } } @@ -410,7 +395,7 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) { } } *pcount = 0; - return NULL; + return nullptr; } #endif @@ -419,7 +404,7 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) { * loaded libraries. gcc_eh does the rest. */ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) { int rv = 0; - for (soinfo* si = solist; si != NULL; si = si->next) { + for (soinfo* si = solist; si != nullptr; si = si->next) { dl_phdr_info dl_info; dl_info.dlpi_addr = si->link_map_head.l_addr; dl_info.dlpi_name = si->link_map_head.l_name; @@ -433,7 +418,7 @@ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void return rv; } -static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name, const SymbolLookupScope& lookup_scope) { +static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) { ElfW(Sym)* symtab = si->symtab; const char* strtab = si->strtab; @@ -444,6 +429,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name, 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: @@ -456,13 +442,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name, static_cast<size_t>(s->st_size)); 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; + continue; default: __libc_fatal("ERROR: Unexpected ST_BIND value: %d for '%s' in '%s'", ELF_ST_BIND(s->st_info), name, si->name); @@ -473,17 +453,33 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name, name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket); - return NULL; + return nullptr; +} + +soinfo::soinfo(const char* name, const struct stat* file_stat) { + memset(this, 0, sizeof(*this)); + + strlcpy(this->name, name, sizeof(this->name)); + flags = FLAG_NEW_SOINFO; + version = SOINFO_VERSION; + + if (file_stat != nullptr) { + set_st_dev(file_stat->st_dev); + set_st_ino(file_stat->st_ino); + } } -static void resolve_ifunc_symbols(soinfo* si) { +void soinfo::resolve_ifunc_symbols() { + if (!get_has_ifuncs()) { + return; + } - phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias); + phdr_table_unprotect_segments(phdr, phnum, load_bias); TRACE_TYPE(IFUNC, "CHECKING FOR IFUNCS AND PERFORMING SYMBOL UPDATES"); - for (size_t i = 0; i < si->nchain; ++i) { - ElfW(Sym)* s = &si->symtab[i]; + for (size_t i = 0; i < nchain; ++i) { + ElfW(Sym)* s = &symtab[i]; if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { // The address of the ifunc in the symbol table is the address of the // function that chooses the function to which the ifunc will refer. @@ -491,12 +487,12 @@ static void resolve_ifunc_symbols(soinfo* si) { // in the linker and then return its result (minus the base offset). TRACE_TYPE(IFUNC, "FOUND IFUNC"); ElfW(Addr) (*ifunc_ptr)(); - ifunc_ptr = reinterpret_cast<ElfW(Addr)(*)()>(s->st_value + si->base); - s->st_value = (ifunc_ptr() - si->base); + ifunc_ptr = reinterpret_cast<ElfW(Addr)(*)()>(s->st_value + base); + s->st_value = (ifunc_ptr() - base); TRACE_TYPE(IFUNC, "NEW VALUE IS %p", (void*)s->st_value); } } - phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias); + phdr_table_protect_segments(phdr, phnum, load_bias); } static unsigned elfhash(const char* _name) { @@ -512,22 +508,31 @@ static unsigned elfhash(const char* _name) { return h; } -static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, soinfo* needed[]) { +static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) { unsigned elf_hash = elfhash(name); - ElfW(Sym)* s = NULL; + ElfW(Sym)* s = nullptr; - if (si != NULL && somain != NULL) { + if (si != nullptr && somain != nullptr) { /* * Local scope is executable scope. Just start looking into it right away * for the shortcut. */ if (si == somain) { - s = soinfo_elf_lookup(si, elf_hash, name, SymbolLookupScope::kAllowLocal); - if (s != NULL) { + s = soinfo_elf_lookup(si, elf_hash, name); + if (s != nullptr) { *lsi = si; goto done; } + + /* 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); + if (s != NULL) { + *lsi = g_ld_preloads[i]; + goto done; + } + } } else { /* Order of symbol lookup is controlled by DT_SYMBOLIC flag */ @@ -540,11 +545,20 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s 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, SymbolLookupScope::kExcludeLocal); - if (s != NULL) { + s = soinfo_elf_lookup(somain, elf_hash, name); + if (s != nullptr) { *lsi = somain; goto done; } + + /* 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); + if (s != NULL) { + *lsi = g_ld_preloads[i]; + goto done; + } + } } /* Look for symbols in the local scope (the object who is @@ -557,8 +571,8 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s * 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, SymbolLookupScope::kAllowLocal); - if (s != NULL) { + s = soinfo_elf_lookup(si, elf_hash, name); + if (s != nullptr) { *lsi = si; goto done; } @@ -571,36 +585,36 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s 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, SymbolLookupScope::kExcludeLocal); - if (s != NULL) { + s = soinfo_elf_lookup(somain, elf_hash, name); + if (s != nullptr) { *lsi = somain; goto done; } - } - } - } - /* 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, SymbolLookupScope::kExcludeLocal); - if (s != NULL) { - *lsi = g_ld_preloads[i]; - goto done; + /* 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); + if (s != NULL) { + *lsi = g_ld_preloads[i]; + goto done; + } + } + } } } - 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, SymbolLookupScope::kExcludeLocal); - if (s != NULL) { - *lsi = needed[i]; - goto done; + si->get_children().visit([&](soinfo* child) { + DEBUG("%s: looking up %s in %s", si->name, name, child->name); + s = soinfo_elf_lookup(child, elf_hash, name); + if (s != nullptr) { + *lsi = child; + return false; } - } + return true; + }); done: - if (s != NULL) { + if (s != nullptr) { TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, " "found in %s, base = %p, load bias = %p", si->name, name, reinterpret_cast<void*>(s->st_value), @@ -609,11 +623,45 @@ done: return s; } - return NULL; + return nullptr; } -// Another soinfo list allocator to use in dlsym. We don't reuse -// SoinfoListAllocator because it is write-protected most of the time. +// Each size has it's own allocator. +template<size_t size> +class SizeBasedAllocator { + public: + static void* alloc() { + return allocator_.alloc(); + } + + static void free(void* ptr) { + allocator_.free(ptr); + } + + private: + static LinkerBlockAllocator allocator_; +}; + +template<size_t size> +LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size); + +template<typename T> +class TypeBasedAllocator { + public: + static T* alloc() { + return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc()); + } + + static void free(T* ptr) { + SizeBasedAllocator<sizeof(T)>::free(ptr); + } +}; + +template <typename T> +using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>; + +typedef linked_list_t<soinfo> SoinfoLinkedList; + static LinkerAllocator<LinkedListEntry<soinfo>> g_soinfo_list_allocator_rw; class SoinfoListAllocatorRW { public: @@ -628,9 +676,10 @@ class SoinfoListAllocatorRW { // This is used by dlsym(3). It performs symbol lookup only within the // specified soinfo object and its dependencies in breadth first order. -ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name, soinfo* caller) { - LinkedList<soinfo, SoinfoListAllocatorRW> visit_list; - LinkedList<soinfo, SoinfoListAllocatorRW> visited; +ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) { + SoinfoLinkedList visit_list; + SoinfoLinkedList visited; + visit_list.push_back(si); soinfo* current_soinfo; while ((current_soinfo = visit_list.pop_front()) != nullptr) { @@ -638,13 +687,10 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name, soi continue; } - ElfW(Sym)* result = soinfo_elf_lookup(current_soinfo, elfhash(name), name, - caller == current_soinfo ? SymbolLookupScope::kAllowLocal : SymbolLookupScope::kExcludeLocal); + ElfW(Sym)* result = soinfo_elf_lookup(current_soinfo, elfhash(name), name); if (result != nullptr) { *found = current_soinfo; - visit_list.clear(); - visited.clear(); return result; } visited.push_back(current_soinfo); @@ -654,8 +700,6 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name, soi }); } - visit_list.clear(); - visited.clear(); return nullptr; } @@ -664,24 +708,23 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name, soi 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, soinfo* caller) { +ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) { unsigned elf_hash = elfhash(name); - if (start == NULL) { + if (start == nullptr) { start = solist; } - ElfW(Sym)* s = NULL; - for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) { - s = soinfo_elf_lookup(si, elf_hash, name, - caller == si ? SymbolLookupScope::kAllowLocal : SymbolLookupScope::kExcludeLocal); - if (s != NULL) { + ElfW(Sym)* s = nullptr; + for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) { + s = soinfo_elf_lookup(si, elf_hash, name); + if (s != nullptr) { *found = si; break; } } - if (s != NULL) { + if (s != nullptr) { TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p", name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base)); } @@ -691,12 +734,12 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start, soinfo* find_containing_library(const void* p) { ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p); - for (soinfo* si = solist; si != NULL; si = si->next) { + for (soinfo* si = solist; si != nullptr; si = si->next) { if (address >= si->base && address - si->base < si->size) { return si; } } - return NULL; + return nullptr; } ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) { @@ -713,12 +756,12 @@ ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) { } } - return NULL; + return nullptr; } static int open_library_on_path(const char* name, const char* const paths[]) { char buf[512]; - for (size_t i = 0; paths[i] != NULL; ++i) { + for (size_t i = 0; paths[i] != nullptr; ++i) { int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name); if (n < 0 || n >= static_cast<int>(sizeof(buf))) { PRINT("Warning: ignoring very long library path: %s/%s", paths[i], name); @@ -736,7 +779,7 @@ static int open_library(const char* name) { TRACE("[ opening %s ]", name); // If the name contains a slash, we should attempt to open it directly and not search the paths. - if (strchr(name, '/') != NULL) { + if (strchr(name, '/') != nullptr) { int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC)); if (fd != -1) { return fd; @@ -759,14 +802,14 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin int fd = -1; ScopedFd file_guard(-1); - if (extinfo != NULL && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { + if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) { fd = extinfo->library_fd; } else { // Open the file. fd = open_library(name); if (fd == -1) { DL_ERR("library \"%s\" not found", name); - return NULL; + return nullptr; } file_guard.reset(fd); @@ -777,12 +820,12 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin struct stat file_stat; if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) { DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno)); - return NULL; + return nullptr; } // Check for symlink and other situations where // file can have different names. - for (soinfo* si = solist; si != NULL; si = si->next) { + for (soinfo* si = solist; si != nullptr; si = si->next) { if (si->get_st_dev() != 0 && si->get_st_ino() != 0 && si->get_st_dev() == file_stat.st_dev && @@ -793,17 +836,17 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin } if ((dlflags & RTLD_NOLOAD) != 0) { - return NULL; + return nullptr; } // Read the ELF header and load the segments. if (!elf_reader.Load(extinfo)) { - return NULL; + return nullptr; } soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat); - if (si == NULL) { - return NULL; + if (si == nullptr) { + return nullptr; } si->base = elf_reader.load_start(); si->size = elf_reader.load_size(); @@ -816,30 +859,26 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin TRACE("[ load_library base=%p size=%zu name='%s' ]", reinterpret_cast<void*>(si->base), si->size, si->name); - if (!soinfo_link_image(si, extinfo)) { + if (!si->LinkImage(extinfo)) { soinfo_free(si); - return NULL; + return nullptr; } - // if the library has any ifuncs, we will need to resolve them so that dlsym - // can handle them properly - resolve_ifunc_symbols(si); - return si; } static soinfo *find_loaded_library_by_name(const char* name) { const char* search_name = SEARCH_NAME(name); - for (soinfo* si = solist; si != NULL; si = si->next) { + for (soinfo* si = solist; si != nullptr; si = si->next) { if (!strcmp(search_name, si->name)) { return si; } } - return NULL; + return nullptr; } static soinfo* find_library_internal(const char* name, int dlflags, const android_dlextinfo* extinfo) { - if (name == NULL) { + if (name == nullptr) { return somain; } @@ -847,14 +886,14 @@ static soinfo* find_library_internal(const char* name, int dlflags, const androi // Library might still be loaded, the accurate detection // of this fact is done by load_library - if (si == NULL) { + if (si == nullptr) { TRACE("[ '%s' has not been found by name. Trying harder...]", name); si = load_library(name, dlflags, extinfo); } - if (si != NULL && (si->flags & FLAG_LINKED) == 0) { + if (si != nullptr && (si->flags & FLAG_LINKED) == 0) { DL_ERR("recursive link to \"%s\"", si->name); - return NULL; + return nullptr; } return si; @@ -862,7 +901,7 @@ static soinfo* find_library_internal(const char* name, int dlflags, const androi static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) { soinfo* si = find_library_internal(name, dlflags, extinfo); - if (si != NULL) { + if (si != nullptr) { si->ref_count++; } return si; @@ -873,18 +912,25 @@ static void soinfo_unload(soinfo* si) { TRACE("unloading '%s'", si->name); si->CallDestructors(); - if ((si->flags | FLAG_NEW_SOINFO) != 0) { - si->get_children().for_each([&] (soinfo* child) { - TRACE("%s needs to unload %s", si->name, child->name); - soinfo_unload(child); - }); + if (si->has_min_version(0)) { + // It is not safe to do si->get_children().for_each, because + // during soinfo_free the child will concurrently modify the si->children + // list, therefore we create a copy and use it to unload children. + size_t children_count = si->get_children().size(); + soinfo* children[children_count]; + si->get_children().copy_to_array(children, children_count); + + for (size_t i = 0; i < children_count; ++i) { + TRACE("%s needs to unload %s", si->name, children[i]->name); + soinfo_unload(children[i]); + } } else { for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { if (d->d_tag == DT_NEEDED) { const char* library_name = si->strtab + d->d_un.d_val; TRACE("%s needs to unload %s", si->name, library_name); - soinfo* needed = find_library(library_name, RTLD_NOLOAD, NULL); - if (needed != NULL) { + soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr); + if (needed != nullptr) { soinfo_unload(needed); } else { // Not found: for example if symlink was deleted between dlopen and dlclose @@ -905,7 +951,21 @@ static void soinfo_unload(soinfo* si) { } void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) { - snprintf(buffer, buffer_size, "%s:%s", kDefaultLdPaths[0], kDefaultLdPaths[1]); + // Use basic string manipulation calls to avoid snprintf. + // snprintf indirectly calls pthread_getspecific to get the size of a buffer. + // When debug malloc is enabled, this call returns 0. This in turn causes + // snprintf to do nothing, which causes libraries to fail to load. + // See b/17302493 for further details. + // Once the above bug is fixed, this code can be modified to use + // snprintf again. + size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2; + if (buffer_size < required_len) { + __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: buffer len %zu, required len %zu", + buffer_size, required_len); + } + char* end = stpcpy(buffer, kDefaultLdPaths[0]); + *end = ':'; + strcpy(end + 1, kDefaultLdPaths[1]); } void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { @@ -917,15 +977,15 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) { soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) { if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NOLOAD)) != 0) { DL_ERR("invalid flags to dlopen: %x", flags); - return NULL; + return nullptr; } - if (extinfo != NULL && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) { + if (extinfo != nullptr && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) { DL_ERR("invalid extended flags to android_dlopen_ext: %" PRIx64, extinfo->flags); - return NULL; + return nullptr; } protect_data(PROT_READ | PROT_WRITE); soinfo* si = find_library(name, flags, extinfo); - if (si != NULL) { + if (si != nullptr) { si->CallConstructors(); } protect_data(PROT_READ); @@ -940,7 +1000,7 @@ void do_dlclose(soinfo* si) { // ifuncs are only defined for x86 #if defined(__i386__) -static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* needed[]) { +static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count) { for (size_t idx = 0; idx < count; ++idx, ++rel) { ElfW(Sym)* s; soinfo* lsi; @@ -948,9 +1008,9 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, so unsigned sym = ELFW(R_SYM)(rel->r_info); ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + si->load_bias); ElfW(Addr) sym_addr = 0; - const char* sym_name = NULL; + const char* sym_name = nullptr; sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name); - s = soinfo_do_lookup(si, sym_name, &lsi, needed); + s = soinfo_do_lookup(si, sym_name, &lsi); if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_386_JMP_SLOT) { TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr)); @@ -963,7 +1023,7 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, so #endif #if defined(__x86_64__) -static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* needed[]) { +static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count) { for (size_t idx = 0; idx < count; ++idx, ++rela) { ElfW(Sym)* s; soinfo* lsi; @@ -971,9 +1031,9 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, unsigned sym = ELFW(R_SYM)(rela->r_info); ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + si->load_bias); ElfW(Addr) sym_addr = 0; - const char* sym_name = NULL; + const char* sym_name = nullptr; sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name); - s = soinfo_do_lookup(si, sym_name, &lsi, needed); + s = soinfo_do_lookup(si, sym_name, &lsi); if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_X86_64_JUMP_SLOT) { TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr + rela->r_addend)); @@ -986,29 +1046,29 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, #endif #if defined(USE_RELA) -static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* needed[]) { +int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) { ElfW(Sym)* s; soinfo* lsi; for (size_t idx = 0; idx < count; ++idx, ++rela) { unsigned type = ELFW(R_TYPE)(rela->r_info); unsigned sym = ELFW(R_SYM)(rela->r_info); - ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + si->load_bias); + ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + load_bias); ElfW(Addr) sym_addr = 0; - const char* sym_name = NULL; + const char* sym_name = nullptr; - DEBUG("Processing '%s' relocation at index %zd", si->name, idx); + DEBUG("Processing '%s' relocation at index %zd", name, idx); if (type == 0) { // R_*_NONE continue; } if (sym != 0) { - sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name); - s = soinfo_do_lookup(si, sym_name, &lsi, needed); - if (s == NULL) { + sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name); + s = soinfo_do_lookup(this, sym_name, &lsi); + if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... - s = &si->symtab[sym]; + s = &symtab[sym]; if (ELF_ST_BIND(s->st_info) != STB_WEAK) { - DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name); + DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name); return -1; } @@ -1060,7 +1120,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* } count_relocation(kRelocSymbol); } else { - s = NULL; + s = nullptr; } switch (type) { @@ -1166,8 +1226,8 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* return -1; } TRACE_TYPE(RELO, "RELO RELATIVE %16llx <- %16llx\n", - reloc, (si->base + rela->r_addend)); - *reinterpret_cast<ElfW(Addr)*>(reloc) = (si->base + rela->r_addend); + reloc, (base + rela->r_addend)); + *reinterpret_cast<ElfW(Addr)*>(reloc) = (base + rela->r_addend); break; case R_AARCH64_COPY: @@ -1180,7 +1240,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* * R_AARCH64_COPY may only appear in executable objects where e_type is * set to ET_EXEC. */ - DL_ERR("%s R_AARCH64_COPY relocations are not supported", si->name); + DL_ERR("%s R_AARCH64_COPY relocations are not supported", name); return -1; case R_AARCH64_TLS_TPREL64: TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n", @@ -1197,7 +1257,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast<size_t>(reloc), static_cast<size_t>(sym_addr + rela->r_addend), sym_name); if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { - si->set_has_ifuncs(true); + set_has_ifuncs(true); } else { *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend; } @@ -1217,8 +1277,8 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* return -1; } TRACE_TYPE(RELO, "RELO RELATIVE %08zx <- +%08zx", static_cast<size_t>(reloc), - static_cast<size_t>(si->base)); - *reinterpret_cast<ElfW(Addr)*>(reloc) = si->base + rela->r_addend; + static_cast<size_t>(base)); + *reinterpret_cast<ElfW(Addr)*>(reloc) = base + rela->r_addend; break; case R_X86_64_32: count_relocation(kRelocRelative); @@ -1253,8 +1313,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* } #else // REL, not RELA. - -static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* needed[]) { +int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) { ElfW(Sym)* s; soinfo* lsi; @@ -1262,22 +1321,22 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n unsigned type = ELFW(R_TYPE)(rel->r_info); // TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead. unsigned sym = ELFW(R_SYM)(rel->r_info); - ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + si->load_bias); + ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias); ElfW(Addr) sym_addr = 0; - const char* sym_name = NULL; + const char* sym_name = nullptr; - DEBUG("Processing '%s' relocation at index %zd", si->name, idx); + DEBUG("Processing '%s' relocation at index %zd", name, idx); if (type == 0) { // R_*_NONE continue; } if (sym != 0) { - sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name); - s = soinfo_do_lookup(si, sym_name, &lsi, needed); - if (s == NULL) { + sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name); + s = soinfo_do_lookup(this, sym_name, &lsi); + if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference... - s = &si->symtab[sym]; + s = &symtab[sym]; if (ELF_ST_BIND(s->st_info) != STB_WEAK) { - DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name); + DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name); return -1; } @@ -1332,7 +1391,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n } count_relocation(kRelocSymbol); } else { - s = NULL; + s = nullptr; } switch (type) { @@ -1372,7 +1431,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n * R_ARM_COPY may only appear in executable objects where e_type is * set to ET_EXEC. */ - DL_ERR("%s R_ARM_COPY relocations are not supported", si->name); + DL_ERR("%s R_ARM_COPY relocations are not supported", name); return -1; #elif defined(__i386__) case R_386_JMP_SLOT: @@ -1380,7 +1439,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name); if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) { - si->set_has_ifuncs(true); + set_has_ifuncs(true); } else { *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr; } @@ -1424,7 +1483,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n if (s) { *reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr; } else { - *reinterpret_cast<ElfW(Addr)*>(reloc) += si->base; + *reinterpret_cast<ElfW(Addr)*>(reloc) += base; } break; #endif @@ -1441,8 +1500,8 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n return -1; } TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p", - reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(si->base)); - *reinterpret_cast<ElfW(Addr)*>(reloc) += si->base; + reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base)); + *reinterpret_cast<ElfW(Addr)*>(reloc) += base; break; default: @@ -1455,9 +1514,9 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n #endif #if defined(__mips__) -static bool mips_relocate_got(soinfo* si, soinfo* needed[]) { +static bool mips_relocate_got(soinfo* si) { ElfW(Addr)** got = si->plt_got; - if (got == NULL) { + if (got == nullptr) { return true; } unsigned local_gotno = si->mips_local_gotno; @@ -1488,8 +1547,8 @@ static bool mips_relocate_got(soinfo* si, soinfo* needed[]) { // This is an undefined reference... try to locate it. const char* sym_name = si->strtab + sym->st_name; soinfo* lsi; - ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, needed); - if (s == NULL) { + ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi); + if (s == nullptr) { // We only allow an undefined symbol if this is a weak reference. s = &symtab[g]; if (ELF_ST_BIND(s->st_info) != STB_WEAK) { @@ -1509,7 +1568,7 @@ static bool mips_relocate_got(soinfo* si, soinfo* needed[]) { #endif void soinfo::CallArray(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) { - if (functions == NULL) { + if (functions == nullptr) { return; } @@ -1528,7 +1587,7 @@ void soinfo::CallArray(const char* array_name __unused, linker_function_t* funct } void soinfo::CallFunction(const char* function_name __unused, linker_function_t function) { - if (function == NULL || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) { + if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) { return; } @@ -1564,7 +1623,7 @@ void soinfo::CallConstructors() { // out above, the libc constructor will be called again (recursively!). constructors_called = true; - if ((flags & FLAG_EXE) == 0 && preinit_array != NULL) { + if ((flags & FLAG_EXE) == 0 && preinit_array != nullptr) { // The GNU dynamic linker silently ignores these, but we warn the developer. PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!", name, preinit_array_count); @@ -1579,6 +1638,8 @@ void soinfo::CallConstructors() { // DT_INIT should be called before DT_INIT_ARRAY if both are present. CallFunction("DT_INIT", init_func); CallArray("DT_INIT_ARRAY", init_array, init_array_count, false); + + resolve_ifunc_symbols(); } void soinfo::CallDestructors() { @@ -1596,16 +1657,14 @@ void soinfo::CallDestructors() { } void soinfo::add_child(soinfo* child) { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return; + if (has_min_version(0)) { + this->children.push_front(child); + child->parents.push_front(this); } - - this->children.push_front(child); - child->parents.push_front(this); } void soinfo::remove_all_links() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { + if (!has_min_version(0)) { return; } @@ -1617,7 +1676,7 @@ void soinfo::remove_all_links() { }); parents.for_each([&] (soinfo* parent) { - parent->children.for_each([&] (const soinfo* child) { + parent->children.remove_if([&] (const soinfo* child) { return child == this; }); }); @@ -1628,51 +1687,45 @@ void soinfo::remove_all_links() { } void soinfo::set_st_dev(dev_t dev) { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return; + if (has_min_version(0)) { + st_dev = dev; } - - st_dev = dev; } void soinfo::set_st_ino(ino_t ino) { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return; + if (has_min_version(0)) { + st_ino = ino; } - - st_ino = ino; } void soinfo::set_has_ifuncs(bool ifuncs) { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return; + if (has_min_version(1)) { + has_ifuncs = ifuncs; } - - has_ifuncs = ifuncs; } dev_t soinfo::get_st_dev() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return 0; + if (has_min_version(0)) { + return st_dev; } - return st_dev; + return 0; }; ino_t soinfo::get_st_ino() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return 0; + if (has_min_version(0)) { + return st_ino; } - return st_ino; + return 0; } bool soinfo::get_has_ifuncs() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return false; + if (has_min_version(1)) { + return has_ifuncs; } - return has_ifuncs; + return false; } // This is a return on get_children() in case @@ -1680,11 +1733,11 @@ bool soinfo::get_has_ifuncs() { static soinfo::soinfo_list_t g_empty_list; soinfo::soinfo_list_t& soinfo::get_children() { - if ((this->flags & FLAG_NEW_SOINFO) == 0) { - return g_empty_list; + if (has_min_version(0)) { + return this->children; } - return this->children; + return g_empty_list; } /* Force any of the closed stdin, stdout and stderr to be associated with @@ -1748,84 +1801,80 @@ static int nullify_closed_stdio() { return return_value; } -static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { - /* "base" might wrap around UINT32_MAX. */ - ElfW(Addr) base = si->load_bias; - const ElfW(Phdr)* phdr = si->phdr; - int phnum = si->phnum; - bool relocating_linker = (si->flags & FLAG_LINKER) != 0; +bool soinfo::LinkImage(const android_dlextinfo* extinfo) { + bool relocating_linker = (flags & FLAG_LINKER) != 0; /* We can't debug anything until the linker is relocated */ if (!relocating_linker) { - INFO("[ linking %s ]", si->name); - DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(si->base), si->flags); + INFO("[ linking %s ]", name); + DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags); } /* Extract dynamic section */ size_t dynamic_count; ElfW(Word) dynamic_flags; - phdr_table_get_dynamic_section(phdr, phnum, base, &si->dynamic, + phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_count, &dynamic_flags); - if (si->dynamic == NULL) { + if (dynamic == nullptr) { if (!relocating_linker) { - DL_ERR("missing PT_DYNAMIC in \"%s\"", si->name); + DL_ERR("missing PT_DYNAMIC in \"%s\"", name); } return false; } else { if (!relocating_linker) { - DEBUG("dynamic = %p", si->dynamic); + DEBUG("dynamic = %p", dynamic); } } #if defined(__arm__) - (void) phdr_table_get_arm_exidx(phdr, phnum, base, - &si->ARM_exidx, &si->ARM_exidx_count); + (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias, + &ARM_exidx, &ARM_exidx_count); #endif // Extract useful information from dynamic section. uint32_t needed_count = 0; - for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { + for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p", d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val)); switch (d->d_tag) { case DT_HASH: - si->nbucket = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr)[0]; - si->nchain = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr)[1]; - si->bucket = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr + 8); - si->chain = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr + 8 + si->nbucket * 4); + nbucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0]; + nchain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1]; + bucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8); + chain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket * 4); break; case DT_STRTAB: - si->strtab = reinterpret_cast<const char*>(base + d->d_un.d_ptr); + strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr); break; case DT_SYMTAB: - si->symtab = reinterpret_cast<ElfW(Sym)*>(base + d->d_un.d_ptr); + symtab = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr); break; #if !defined(__LP64__) case DT_PLTREL: if (d->d_un.d_val != DT_REL) { - DL_ERR("unsupported DT_RELA in \"%s\"", si->name); + DL_ERR("unsupported DT_RELA in \"%s\"", name); return false; } break; #endif case DT_JMPREL: #if defined(USE_RELA) - si->plt_rela = reinterpret_cast<ElfW(Rela)*>(base + d->d_un.d_ptr); + plt_rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); #else - si->plt_rel = reinterpret_cast<ElfW(Rel)*>(base + d->d_un.d_ptr); + plt_rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); #endif break; case DT_PLTRELSZ: #if defined(USE_RELA) - si->plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); + plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); #else - si->plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); + plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); #endif break; #if defined(__mips__) case DT_PLTGOT: // Used by mips and mips64. - si->plt_got = reinterpret_cast<ElfW(Addr)**>(base + d->d_un.d_ptr); + plt_got = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr); break; #endif case DT_DEBUG: @@ -1843,67 +1892,67 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { #endif #if defined(USE_RELA) case DT_RELA: - si->rela = reinterpret_cast<ElfW(Rela)*>(base + d->d_un.d_ptr); + rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr); break; case DT_RELASZ: - si->rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); + rela_count = d->d_un.d_val / sizeof(ElfW(Rela)); break; case DT_REL: - DL_ERR("unsupported DT_REL in \"%s\"", si->name); + DL_ERR("unsupported DT_REL in \"%s\"", name); return false; case DT_RELSZ: - DL_ERR("unsupported DT_RELSZ in \"%s\"", si->name); + DL_ERR("unsupported DT_RELSZ in \"%s\"", name); return false; #else case DT_REL: - si->rel = reinterpret_cast<ElfW(Rel)*>(base + d->d_un.d_ptr); + rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr); break; case DT_RELSZ: - si->rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); + rel_count = d->d_un.d_val / sizeof(ElfW(Rel)); break; case DT_RELA: - DL_ERR("unsupported DT_RELA in \"%s\"", si->name); + DL_ERR("unsupported DT_RELA in \"%s\"", name); return false; #endif case DT_INIT: - si->init_func = reinterpret_cast<linker_function_t>(base + d->d_un.d_ptr); - DEBUG("%s constructors (DT_INIT) found at %p", si->name, si->init_func); + init_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); + DEBUG("%s constructors (DT_INIT) found at %p", name, init_func); break; case DT_FINI: - si->fini_func = reinterpret_cast<linker_function_t>(base + d->d_un.d_ptr); - DEBUG("%s destructors (DT_FINI) found at %p", si->name, si->fini_func); + fini_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr); + DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func); break; case DT_INIT_ARRAY: - si->init_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr); - DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", si->name, si->init_array); + init_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); + DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array); break; case DT_INIT_ARRAYSZ: - si->init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); + init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); break; case DT_FINI_ARRAY: - si->fini_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr); - DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", si->name, si->fini_array); + fini_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); + DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array); break; case DT_FINI_ARRAYSZ: - si->fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); + fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); break; case DT_PREINIT_ARRAY: - si->preinit_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr); - DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", si->name, si->preinit_array); + preinit_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr); + DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array); break; case DT_PREINIT_ARRAYSZ: - si->preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); + preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr)); break; case DT_TEXTREL: #if defined(__LP64__) - DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", si->name); + DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name); return false; #else - si->has_text_relocations = true; + has_text_relocations = true; break; #endif case DT_SYMBOLIC: - si->has_DT_SYMBOLIC = true; + has_DT_SYMBOLIC = true; break; case DT_NEEDED: ++needed_count; @@ -1911,14 +1960,14 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { case DT_FLAGS: if (d->d_un.d_val & DF_TEXTREL) { #if defined(__LP64__) - DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", si->name); + DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name); return false; #else - si->has_text_relocations = true; + has_text_relocations = true; #endif } if (d->d_un.d_val & DF_SYMBOLIC) { - si->has_DT_SYMBOLIC = true; + has_DT_SYMBOLIC = true; } break; #if defined(__mips__) @@ -1929,7 +1978,7 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { case DT_MIPS_RLD_MAP: // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB. { - r_debug** dp = reinterpret_cast<r_debug**>(base + d->d_un.d_ptr); + r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr); *dp = &_r_debug; } break; @@ -1940,15 +1989,15 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { break; case DT_MIPS_SYMTABNO: - si->mips_symtabno = d->d_un.d_val; + mips_symtabno = d->d_un.d_val; break; case DT_MIPS_LOCAL_GOTNO: - si->mips_local_gotno = d->d_un.d_val; + mips_local_gotno = d->d_un.d_val; break; case DT_MIPS_GOTSYM: - si->mips_gotsym = d->d_un.d_val; + mips_gotsym = d->d_un.d_val; break; #endif @@ -1960,100 +2009,95 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { } DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", - reinterpret_cast<void*>(si->base), si->strtab, si->symtab); + reinterpret_cast<void*>(base), strtab, symtab); // Sanity checks. if (relocating_linker && needed_count != 0) { DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries"); return false; } - if (si->nbucket == 0) { - DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", si->name); + if (nbucket == 0) { + DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", name); return false; } - if (si->strtab == 0) { - DL_ERR("empty/missing DT_STRTAB in \"%s\"", si->name); + if (strtab == 0) { + DL_ERR("empty/missing DT_STRTAB in \"%s\"", name); return false; } - if (si->symtab == 0) { - DL_ERR("empty/missing DT_SYMTAB in \"%s\"", si->name); + if (symtab == 0) { + DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name); return false; } // If this is the main executable, then load all of the libraries from LD_PRELOAD now. - if (si->flags & FLAG_EXE) { + if (flags & FLAG_EXE) { memset(g_ld_preloads, 0, sizeof(g_ld_preloads)); size_t preload_count = 0; - for (size_t i = 0; g_ld_preload_names[i] != NULL; i++) { - soinfo* lsi = find_library(g_ld_preload_names[i], 0, NULL); - if (lsi != NULL) { + for (size_t i = 0; g_ld_preload_names[i] != nullptr; i++) { + soinfo* lsi = find_library(g_ld_preload_names[i], 0, nullptr); + if (lsi != nullptr) { g_ld_preloads[preload_count++] = lsi; } else { // As with glibc, failure to load an LD_PRELOAD library is just a warning. DL_WARN("could not load library \"%s\" from LD_PRELOAD for \"%s\"; caused by %s", - g_ld_preload_names[i], si->name, linker_get_error_buffer()); + g_ld_preload_names[i], name, linker_get_error_buffer()); } } } - soinfo** needed = reinterpret_cast<soinfo**>(alloca((1 + needed_count) * sizeof(soinfo*))); - soinfo** pneeded = needed; - - for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) { + for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) { if (d->d_tag == DT_NEEDED) { - const char* library_name = si->strtab + d->d_un.d_val; - DEBUG("%s needs %s", si->name, library_name); - soinfo* lsi = find_library(library_name, 0, NULL); - if (lsi == NULL) { + const char* library_name = strtab + d->d_un.d_val; + DEBUG("%s needs %s", name, library_name); + soinfo* lsi = find_library(library_name, 0, nullptr); + if (lsi == nullptr) { strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf)); DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s", - library_name, si->name, tmp_err_buf); + library_name, name, tmp_err_buf); return false; } - si->add_child(lsi); - *pneeded++ = lsi; + add_child(lsi); } } - *pneeded = NULL; #if !defined(__LP64__) - if (si->has_text_relocations) { + if (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. DL_WARN("%s has text relocations. This is wasting memory and prevents " - "security hardening. Please fix.", si->name); - if (phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias) < 0) { + "security hardening. Please fix.", name); + if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) { DL_ERR("can't unprotect loadable segments for \"%s\": %s", - si->name, strerror(errno)); + name, strerror(errno)); return false; } } #endif #if defined(USE_RELA) - if (si->plt_rela != NULL) { - DEBUG("[ relocating %s plt ]\n", si->name); - if (soinfo_relocate(si, si->plt_rela, si->plt_rela_count, needed)) { + if (plt_rela != nullptr) { + DEBUG("[ relocating %s plt ]\n", name); + if (Relocate(plt_rela, plt_rela_count)) { return false; } } - if (si->rela != NULL) { - DEBUG("[ relocating %s ]\n", si->name); - if (soinfo_relocate(si, si->rela, si->rela_count, needed)) { + if (rela != nullptr) { + DEBUG("[ relocating %s ]\n", name); + if (Relocate(rela, rela_count)) { return false; } } #else - if (si->plt_rel != NULL) { - DEBUG("[ relocating %s plt ]", si->name); - if (soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) { + if (plt_rel != nullptr) { + DEBUG("[ relocating %s plt ]", name); + if (Relocate(plt_rel, plt_rel_count)) { return false; } } - if (si->rel != NULL) { - DEBUG("[ relocating %s ]", si->name); - if (soinfo_relocate(si, si->rel, si->rel_count, needed)) { + if (rel != nullptr) { + DEBUG("[ relocating %s ]", name); + if (Relocate(rel, rel_count)) { return false; } } @@ -2063,59 +2107,59 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { // they cannot be resolved until the rest of the relocations are done // because we need to call the resolution function which may be waiting // on relocations. - if(si->get_has_ifuncs()) { + if(get_has_ifuncs()) { #if defined(__i386__) - soinfo_ifunc_relocate(si, si->plt_rel, si->plt_rel_count, needed); + soinfo_ifunc_relocate(this, plt_rel, plt_rel_count); #elif defined(__x86_64__) - soinfo_ifunc_relocate(si, si->plt_rela, si->plt_rela_count, needed); + soinfo_ifunc_relocate(this, plt_rela, plt_rela_count); #endif } #if defined(__mips__) - if (!mips_relocate_got(si, needed)) { + if (!mips_relocate_got(this)) { return false; } #endif - si->flags |= FLAG_LINKED; - DEBUG("[ finished linking %s ]", si->name); + flags |= FLAG_LINKED; + DEBUG("[ finished linking %s ]", name); #if !defined(__LP64__) - if (si->has_text_relocations) { + if (has_text_relocations) { // All relocations are done, we can protect our segments back to read-only. - if (phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias) < 0) { + if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) { DL_ERR("can't protect segments for \"%s\": %s", - si->name, strerror(errno)); + name, strerror(errno)); return false; } } #endif /* We can also turn on GNU RELRO protection */ - if (phdr_table_protect_gnu_relro(si->phdr, si->phnum, si->load_bias) < 0) { + if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) { DL_ERR("can't enable GNU RELRO protection for \"%s\": %s", - si->name, strerror(errno)); + name, strerror(errno)); return false; } /* Handle serializing/sharing the RELRO segment */ if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) { - if (phdr_table_serialize_gnu_relro(si->phdr, si->phnum, si->load_bias, + if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias, extinfo->relro_fd) < 0) { DL_ERR("failed serializing GNU RELRO section for \"%s\": %s", - si->name, strerror(errno)); + name, strerror(errno)); return false; } } else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) { - if (phdr_table_map_gnu_relro(si->phdr, si->phnum, si->load_bias, + if (phdr_table_map_gnu_relro(phdr, phnum, load_bias, extinfo->relro_fd) < 0) { DL_ERR("failed mapping GNU RELRO section for \"%s\": %s", - si->name, strerror(errno)); + name, strerror(errno)); return false; } } - notify_gdb_of_load(si); + notify_gdb_of_load(this); return true; } @@ -2127,11 +2171,11 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) { static void add_vdso(KernelArgumentBlock& args __unused) { #if defined(AT_SYSINFO_EHDR) ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR)); - if (ehdr_vdso == NULL) { + if (ehdr_vdso == nullptr) { return; } - soinfo* si = soinfo_alloc("[vdso]", NULL); + soinfo* si = soinfo_alloc("[vdso]", nullptr); si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff); si->phnum = ehdr_vdso->e_phnum; @@ -2139,14 +2183,19 @@ static void add_vdso(KernelArgumentBlock& args __unused) { si->size = phdr_table_get_load_size(si->phdr, si->phnum); si->load_bias = get_elf_exec_load_bias(ehdr_vdso); - soinfo_link_image(si, NULL); + si->LinkImage(nullptr); #endif } /* * This is linker soinfo for GDB. See details below. */ -static soinfo linker_soinfo_for_gdb; +#if defined(__LP64__) +#define LINKER_PATH "/system/bin/linker64" +#else +#define LINKER_PATH "/system/bin/linker" +#endif +static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr); /* gdb expects the linker to be in the debug shared object list. * Without this, gdb has trouble locating the linker's ".text" @@ -2156,12 +2205,6 @@ static soinfo linker_soinfo_for_gdb; * be on the soinfo list. */ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { -#if defined(__LP64__) - strlcpy(linker_soinfo_for_gdb.name, "/system/bin/linker64", sizeof(linker_soinfo_for_gdb.name)); -#else - strlcpy(linker_soinfo_for_gdb.name, "/system/bin/linker", sizeof(linker_soinfo_for_gdb.name)); -#endif - linker_soinfo_for_gdb.flags = FLAG_NEW_SOINFO; linker_soinfo_for_gdb.base = linker_base; /* @@ -2173,7 +2216,7 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base); ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff); phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base, - &linker_soinfo_for_gdb.dynamic, NULL, NULL); + &linker_soinfo_for_gdb.dynamic, nullptr, nullptr); insert_soinfo_into_debug_map(&linker_soinfo_for_gdb); } @@ -2183,16 +2226,6 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) { * and other non-local data at this point. */ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) { - /* NOTE: we store the args pointer on a special location - * of the temporary TLS area in order to pass it to - * the C Library's runtime initializer. - * - * The initializer must clear the slot and reset the TLS - * to point to a different location to ensure that no other - * shared library constructor can access it. - */ - __libc_init_tls(args); - #if TIMING struct timeval t0, t1; gettimeofday(&t0, 0); @@ -2211,14 +2244,14 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( // Get a few environment variables. const char* LD_DEBUG = linker_env_get("LD_DEBUG"); - if (LD_DEBUG != NULL) { + if (LD_DEBUG != nullptr) { g_ld_debug_verbosity = atoi(LD_DEBUG); } // Normally, these are cleaned by linker_env_init, but the test // doesn't cost us anything. - const char* ldpath_env = NULL; - const char* ldpreload_env = NULL; + const char* ldpath_env = nullptr; + const char* ldpreload_env = nullptr; if (!get_AT_SECURE()) { ldpath_env = linker_env_get("LD_LIBRARY_PATH"); ldpreload_env = linker_env_get("LD_PRELOAD"); @@ -2226,8 +2259,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( INFO("[ android linker & debugger ]"); - soinfo* si = soinfo_alloc(args.argv[0], NULL); - if (si == NULL) { + soinfo* si = soinfo_alloc(args.argv[0], nullptr); + if (si == nullptr) { exit(EXIT_FAILURE); } @@ -2237,8 +2270,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( map->l_addr = 0; map->l_name = args.argv[0]; - map->l_prev = NULL; - map->l_next = NULL; + map->l_prev = nullptr; + map->l_next = nullptr; _r_debug.r_map = map; r_debug_tail = map; @@ -2264,7 +2297,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( break; } } - si->dynamic = NULL; + si->dynamic = nullptr; si->ref_count = 1; ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base); @@ -2279,7 +2312,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( somain = si; - if (!soinfo_link_image(si, NULL)) { + if (!si->LinkImage(nullptr)) { __libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer()); exit(EXIT_FAILURE); } @@ -2288,11 +2321,11 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( si->CallPreInitConstructors(); - for (size_t i = 0; g_ld_preloads[i] != NULL; ++i) { + for (size_t i = 0; g_ld_preloads[i] != nullptr; ++i) { g_ld_preloads[i]->CallConstructors(); } - /* After the link_image, the si->load_bias is initialized. + /* After the LinkImage, the si->load_bias is initialized. * For so lib, the map->l_addr will be updated in notify_gdb_of_load. * We need to update this value for so exe here. So Unwind_Backtrace * for some arch like x86 could work correctly within so exe. @@ -2301,7 +2334,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( si->CallConstructors(); #if TIMING - gettimeofday(&t1, NULL); + gettimeofday(&t1, nullptr); PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) ( (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec))); @@ -2380,10 +2413,6 @@ extern "C" void _start(); * function, or other GOT reference will generate a segfault. */ extern "C" ElfW(Addr) __linker_init(void* raw_args) { - // Initialize static variables. - solist = get_libdl_info(); - sonext = get_libdl_info(); - KernelArgumentBlock args(raw_args); ElfW(Addr) linker_addr = args.getauxval(AT_BASE); @@ -2391,8 +2420,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff); - soinfo linker_so; - memset(&linker_so, 0, sizeof(soinfo)); + soinfo linker_so("[dynamic linker]", nullptr); // If the linker is not acting as PT_INTERP entry_point is equal to // _start. Which means that the linker is running as an executable and @@ -2404,16 +2432,15 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { __libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]); } - strcpy(linker_so.name, "[dynamic linker]"); linker_so.base = linker_addr; linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); - linker_so.dynamic = NULL; + linker_so.dynamic = nullptr; linker_so.phdr = phdr; linker_so.phnum = elf_hdr->e_phnum; linker_so.flags |= FLAG_LINKER; - if (!soinfo_link_image(&linker_so, NULL)) { + if (!linker_so.LinkImage(nullptr)) { // It would be nice to print an error message, but if the linker // can't link itself, there's no guarantee that we'll be able to // call write() (because it involves a GOT reference). We may as @@ -2425,9 +2452,17 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { _exit(EXIT_FAILURE); } + __libc_init_tls(args); + // Initialize the linker's own global variables linker_so.CallConstructors(); + // Initialize static variables. Note that in order to + // get correct libdl_info we need to call constructors + // before get_libdl_info(). + solist = get_libdl_info(); + sonext = get_libdl_info(); + // We have successfully fixed our own relocations. It's safe to run // the main part of the linker now. args.abort_message_ptr = &g_abort_message; diff --git a/linker/linker.h b/linker/linker.h index 0ea1f0301..6547d685e 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -30,6 +30,7 @@ #define _LINKER_H_ #include <elf.h> +#include <inttypes.h> #include <link.h> #include <unistd.h> #include <android/dlext.h> @@ -88,6 +89,8 @@ #define FLAG_LINKER 0x00000010 // The linker itself #define FLAG_NEW_SOINFO 0x40000000 // new soinfo format +#define SOINFO_VERSION 1 + #define SOINFO_NAME_LEN 128 typedef void (*linker_function_t)(); @@ -195,9 +198,13 @@ struct soinfo { bool has_text_relocations; #endif bool has_DT_SYMBOLIC; + + soinfo(const char* name, const struct stat* file_stat); + void CallConstructors(); void CallDestructors(); void CallPreInitConstructors(); + bool LinkImage(const android_dlextinfo* extinfo); void add_child(soinfo* child); void remove_all_links(); @@ -209,21 +216,27 @@ struct soinfo { dev_t get_st_dev(); bool get_has_ifuncs(); - - soinfo_list_t& get_children(); + bool inline has_min_version(uint32_t min_version) { + return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version; + } private: void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse); void CallFunction(const char* function_name, linker_function_t function); + void resolve_ifunc_symbols(); +#if defined(USE_RELA) + int Relocate(ElfW(Rela)* rela, unsigned count); +#else + int Relocate(ElfW(Rel)* rel, unsigned count); +#endif private: // This part of the structure is only available // when FLAG_NEW_SOINFO is set in this->flags. - unsigned int version; - - bool has_ifuncs; + uint32_t version; + // version >= 0 dev_t st_dev; ino_t st_ino; @@ -231,6 +244,8 @@ struct soinfo { soinfo_list_t children; soinfo_list_t parents; + // version >= 1 + bool has_ifuncs; }; extern soinfo* get_libdl_info(); @@ -240,11 +255,11 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path); 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, soinfo* caller_si); +ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start); soinfo* find_containing_library(const void* addr); ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr); -ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name, soinfo* caller_si); +ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name); void debuggerd_init(); extern "C" abort_msg_t* g_abort_message; diff --git a/linker/linker_environ.cpp b/linker/linker_environ.cpp index 846624b9a..daee56f7e 100644 --- a/linker/linker_environ.cpp +++ b/linker/linker_environ.cpp @@ -58,7 +58,7 @@ static void __init_AT_SECURE(KernelArgumentBlock& args) { // Check if the environment variable definition at 'envstr' // starts with '<name>=', and if so return the address of the -// first character after the equal sign. Otherwise return NULL. +// first character after the equal sign. Otherwise return null. static const char* env_match(const char* envstr, const char* name) { size_t i = 0; @@ -70,7 +70,7 @@ static const char* env_match(const char* envstr, const char* name) { return envstr + i + 1; } - return NULL; + return nullptr; } static bool __is_valid_environment_variable(const char* name) { @@ -78,7 +78,7 @@ static bool __is_valid_environment_variable(const char* name) { // as the maximum size for an env. variable definition. const int MAX_ENV_LEN = 32*4096; - if (name == NULL) { + if (name == nullptr) { return false; } @@ -136,10 +136,10 @@ static bool __is_unsafe_environment_variable(const char* name) { "RES_OPTIONS", "TMPDIR", "TZDIR", - NULL + nullptr }; - for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != NULL; ++i) { - if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != NULL) { + for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != nullptr; ++i) { + if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != nullptr) { return true; } } @@ -149,7 +149,7 @@ static bool __is_unsafe_environment_variable(const char* name) { static void __sanitize_environment_variables() { char** src = _envp; char** dst = _envp; - for (; src[0] != NULL; ++src) { + for (; src[0] != nullptr; ++src) { if (!__is_valid_environment_variable(src[0])) { continue; } @@ -160,11 +160,11 @@ static void __sanitize_environment_variables() { dst[0] = src[0]; ++dst; } - dst[0] = NULL; + dst[0] = nullptr; } void linker_env_init(KernelArgumentBlock& args) { - // Store environment pointer - can't be NULL. + // Store environment pointer - can't be null. _envp = args.envp; __init_AT_SECURE(args); @@ -172,18 +172,18 @@ void linker_env_init(KernelArgumentBlock& args) { } const char* linker_env_get(const char* name) { - if (name == NULL || name[0] == '\0') { - return NULL; + if (name == nullptr || name[0] == '\0') { + return nullptr; } - for (char** p = _envp; p[0] != NULL; ++p) { + for (char** p = _envp; p[0] != nullptr; ++p) { const char* val = env_match(p[0], name); - if (val != NULL) { + if (val != nullptr) { if (val[0] == '\0') { - return NULL; // Return NULL for empty strings. + return nullptr; // Return null for empty strings. } return val; } } - return NULL; + return nullptr; } diff --git a/linker/linker_environ.h b/linker/linker_environ.h index d3f54fd08..0f6ac084d 100644 --- a/linker/linker_environ.h +++ b/linker/linker_environ.h @@ -35,7 +35,7 @@ class KernelArgumentBlock; extern void linker_env_init(KernelArgumentBlock& args); // Returns the value of environment variable 'name' if defined and not -// empty, or NULL otherwise. +// empty, or null otherwise. extern const char* linker_env_get(const char* name); // Returns the value of this program's AT_SECURE variable. diff --git a/tests/libs/dlsym_local_symbol.map b/linker/linker_libc_support.c index 58a2299a8..17db6d4e7 100644 --- a/tests/libs/dlsym_local_symbol.map +++ b/linker/linker_libc_support.c @@ -13,10 +13,5 @@ * 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: - *; -}; + +#include "../libc/arch-common/bionic/__dso_handle.h" diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 0b99d2065..1bbd57778 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -121,13 +121,13 @@ ElfReader::ElfReader(const char* name, int fd) : name_(name), fd_(fd), - phdr_num_(0), phdr_mmap_(NULL), phdr_table_(NULL), phdr_size_(0), - load_start_(NULL), load_size_(0), load_bias_(0), - loaded_phdr_(NULL) { + phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0), + load_start_(nullptr), load_size_(0), load_bias_(0), + loaded_phdr_(nullptr) { } ElfReader::~ElfReader() { - if (phdr_mmap_ != NULL) { + if (phdr_mmap_ != nullptr) { munmap(phdr_mmap_, phdr_size_); } } @@ -225,7 +225,7 @@ bool ElfReader::ReadProgramHeader() { phdr_size_ = page_max - page_min; - void* mmap_result = mmap(NULL, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min); + void* mmap_result = mmap(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min); if (mmap_result == MAP_FAILED) { DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno)); return false; @@ -242,7 +242,7 @@ bool ElfReader::ReadProgramHeader() { * process' address space. If there are no loadable segments, 0 is * returned. * - * If out_min_vaddr or out_max_vaddr are non-NULL, they will be + * If out_min_vaddr or out_max_vaddr are not null, they will be * set to the minimum and maximum addresses of pages to be reserved, * or 0 if there is nothing to load. */ @@ -276,10 +276,10 @@ size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count, min_vaddr = PAGE_START(min_vaddr); max_vaddr = PAGE_END(max_vaddr); - if (out_min_vaddr != NULL) { + if (out_min_vaddr != nullptr) { *out_min_vaddr = min_vaddr; } - if (out_max_vaddr != NULL) { + if (out_max_vaddr != nullptr) { *out_max_vaddr = max_vaddr; } return max_vaddr - min_vaddr; @@ -301,7 +301,7 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) { size_t reserved_size = 0; bool reserved_hint = true; - if (extinfo != NULL) { + if (extinfo != nullptr) { if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) { reserved_size = extinfo->reserved_size; reserved_hint = false; @@ -585,9 +585,9 @@ int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, El return -1; } off_t file_size = file_stat.st_size; - void* temp_mapping = NULL; + void* temp_mapping = nullptr; if (file_size > 0) { - temp_mapping = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0); + temp_mapping = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0); if (temp_mapping == MAP_FAILED) { return -1; } @@ -667,7 +667,7 @@ int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, El * phdr_count -> number of entries in tables * load_bias -> load bias * Output: - * arm_exidx -> address of table in memory (NULL on failure). + * arm_exidx -> address of table in memory (null on failure). * arm_exidx_count -> number of items in table (0 on failure). * Return: * 0 on error, -1 on failure (_no_ error code in errno) @@ -687,21 +687,21 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, *arm_exidx_count = (unsigned)(phdr->p_memsz / 8); return 0; } - *arm_exidx = NULL; + *arm_exidx = nullptr; *arm_exidx_count = 0; return -1; } #endif /* Return the address and size of the ELF file's .dynamic section in memory, - * or NULL if missing. + * or null if missing. * * Input: * phdr_table -> program header table * phdr_count -> number of entries in tables * load_bias -> load bias * Output: - * dynamic -> address of table in memory (NULL on failure). + * dynamic -> address of table in memory (null on failure). * dynamic_count -> number of items in table (0 on failure). * dynamic_flags -> protection flags for section (unset on failure) * Return: @@ -727,7 +727,7 @@ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_co } return; } - *dynamic = NULL; + *dynamic = nullptr; if (dynamic_count) { *dynamic_count = 0; } diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index 611f1a7cb..50708a0e6 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -81,7 +81,7 @@ class ElfReader { }; size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count, - ElfW(Addr)* min_vaddr = NULL, ElfW(Addr)* max_vaddr = NULL); + ElfW(Addr)* min_vaddr = nullptr, ElfW(Addr)* max_vaddr = nullptr); int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias); diff --git a/linker/tests/linked_list_test.cpp b/linker/tests/linked_list_test.cpp index b9816fa10..a555edb33 100644 --- a/linker/tests/linked_list_test.cpp +++ b/linker/tests/linked_list_test.cpp @@ -80,7 +80,7 @@ TEST(linked_list, simple) { }); ASSERT_TRUE(!alloc_called); - ASSERT_TRUE(!free_called); + ASSERT_TRUE(free_called); ASSERT_EQ("dba", test_list_to_string(list)); alloc_called = free_called = false; @@ -103,15 +103,118 @@ TEST(linked_list, push_pop) { ASSERT_EQ("ab", test_list_to_string(list)); list.push_back("c"); ASSERT_EQ("abc", test_list_to_string(list)); - ASSERT_EQ("a", list.pop_front()); + ASSERT_STREQ("a", list.pop_front()); ASSERT_EQ("bc", test_list_to_string(list)); - ASSERT_EQ("b", list.pop_front()); + ASSERT_STREQ("b", list.pop_front()); ASSERT_EQ("c", test_list_to_string(list)); - ASSERT_EQ("c", list.pop_front()); + ASSERT_STREQ("c", list.pop_front()); ASSERT_EQ("", test_list_to_string(list)); ASSERT_TRUE(list.pop_front() == nullptr); list.push_back("r"); ASSERT_EQ("r", test_list_to_string(list)); - ASSERT_EQ("r", list.pop_front()); + ASSERT_STREQ("r", list.pop_front()); + ASSERT_TRUE(list.pop_front() == nullptr); +} + +TEST(linked_list, remove_if_then_pop) { + test_list_t list; + list.push_back("a"); + list.push_back("b"); + list.push_back("c"); + list.push_back("d"); + list.remove_if([](const char* c) { + return *c == 'b' || *c == 'c'; + }); + + ASSERT_EQ("ad", test_list_to_string(list)); + ASSERT_STREQ("a", list.pop_front()); + ASSERT_EQ("d", test_list_to_string(list)); + ASSERT_STREQ("d", list.pop_front()); ASSERT_TRUE(list.pop_front() == nullptr); } + +TEST(linked_list, copy_to_array) { + test_list_t list; + const size_t max_size = 128; + const char* buf[max_size]; + memset(buf, 0, sizeof(buf)); + + ASSERT_EQ(0U, list.size()); + ASSERT_EQ(0U, list.copy_to_array(buf, max_size)); + ASSERT_EQ(nullptr, buf[0]); + + list.push_back("a"); + list.push_back("b"); + list.push_back("c"); + list.push_back("d"); + + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(4U, list.size()); + ASSERT_EQ(2U, list.copy_to_array(buf, 2)); + ASSERT_STREQ("a", buf[0]); + ASSERT_STREQ("b", buf[1]); + ASSERT_EQ(nullptr, buf[2]); + + ASSERT_EQ(4U, list.copy_to_array(buf, max_size)); + ASSERT_STREQ("a", buf[0]); + ASSERT_STREQ("b", buf[1]); + ASSERT_STREQ("c", buf[2]); + ASSERT_STREQ("d", buf[3]); + ASSERT_EQ(nullptr, buf[4]); + + memset(buf, 0, sizeof(buf)); + list.remove_if([](const char* c) { + return *c != 'c'; + }); + ASSERT_EQ(1U, list.size()); + ASSERT_EQ(1U, list.copy_to_array(buf, max_size)); + ASSERT_STREQ("c", buf[0]); + ASSERT_EQ(nullptr, buf[1]); + + memset(buf, 0, sizeof(buf)); + + list.remove_if([](const char* c) { + return *c == 'c'; + }); + + ASSERT_EQ(0U, list.size()); + ASSERT_EQ(0U, list.copy_to_array(buf, max_size)); + ASSERT_EQ(nullptr, buf[0]); +} + +TEST(linked_list, test_visit) { + test_list_t list; + list.push_back("a"); + list.push_back("b"); + list.push_back("c"); + list.push_back("d"); + + int visits = 0; + std::stringstream ss; + bool result = list.visit([&](const char* c) { + ++visits; + ss << c; + return true; + }); + + ASSERT_TRUE(result); + ASSERT_EQ(4, visits); + ASSERT_EQ("abcd", ss.str()); + + visits = 0; + ss.str(std::string()); + + result = list.visit([&](const char* c) { + if (++visits == 3) { + return false; + } + + ss << c; + return true; + }); + + ASSERT_TRUE(!result); + ASSERT_EQ(3, visits); + ASSERT_EQ("ab", ss.str()); +} + diff --git a/tests/Android.mk b/tests/Android.mk index b370b92c1..26014aca3 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -92,8 +92,10 @@ libBionicStandardTests_src_files := \ stdatomic_test.cpp \ stdint_test.cpp \ stdio_test.cpp \ + stdio_ext_test.cpp \ stdlib_test.cpp \ string_test.cpp \ + string_posix_strerror_r_test.cpp \ strings_test.cpp \ stubs_test.cpp \ sstream_test.cpp \ @@ -129,6 +131,7 @@ libBionicStandardTests_cppflags := \ libBionicStandardTests_c_includes := \ bionic/libc \ + external/tinyxml2 \ libBionicStandardTests_ldlibs_host := \ -lrt \ @@ -237,11 +240,16 @@ include $(LOCAL_PATH)/Android.build.mk # ----------------------------------------------------------------------------- # Tests for the device using bionic's .so. Run with: -# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests +# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32 +# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests64 # ----------------------------------------------------------------------------- bionic-unit-tests_whole_static_libraries := \ libBionicTests \ +bionic-unit-tests_static_libraries := \ + libtinyxml2 \ + liblog \ + bionic-unit-tests_src_files := \ atexit_test.cpp \ dlext_test.cpp \ @@ -269,7 +277,8 @@ include $(LOCAL_PATH)/Android.build.mk # ----------------------------------------------------------------------------- # Tests for the device linked against bionic's static library. Run with: -# adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static +# adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static32 +# adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static64 # ----------------------------------------------------------------------------- bionic-unit-tests-static_whole_static_libraries := \ libBionicTests \ @@ -279,6 +288,8 @@ bionic-unit-tests-static_static_libraries := \ libm \ libc \ libstdc++ \ + libtinyxml2 \ + liblog \ bionic-unit-tests-static_force_static_executable := true @@ -354,6 +365,22 @@ bionic-unit-tests-run-on-host: bionic-unit-tests $(TARGET_OUT_EXECUTABLES)/$(LIN $(TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests$(NATIVE_TEST_SUFFIX) $(BIONIC_TEST_FLAGS) endif +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86_64)) +# add target to run lp32 tests +bionic-unit-tests-run-on-host32: bionic-unit-tests_32 $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT_EXECUTABLES)/sh + if [ ! -d /system -o ! -d /system/bin ]; then \ + echo "Attempting to create /system/bin"; \ + sudo mkdir -p -m 0777 /system/bin; \ + fi + mkdir -p $(TARGET_OUT_DATA)/local/tmp + cp $(TARGET_OUT_EXECUTABLES)/linker /system/bin + cp $(TARGET_OUT_EXECUTABLES)/sh /system/bin + ANDROID_DATA=$(TARGET_OUT_DATA) \ + ANDROID_ROOT=$(TARGET_OUT) \ + LD_LIBRARY_PATH=$(2ND_TARGET_OUT_SHARED_LIBRARIES) \ + $(2ND_TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests32 $(BIONIC_TEST_FLAGS) +endif + endif # linux-x86 include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/atexit_test.cpp b/tests/atexit_test.cpp index e01220e1b..e92889d1c 100644 --- a/tests/atexit_test.cpp +++ b/tests/atexit_test.cpp @@ -24,20 +24,33 @@ #include <string> -TEST(atexit, dlclose) { +TEST(atexit, sofile) { std::string atexit_call_sequence; bool valid_this_in_static_dtor = false; + bool attr_dtor_called = false; + void* handle = dlopen("libtest_atexit.so", RTLD_NOW); - ASSERT_TRUE(handle != NULL); + ASSERT_TRUE(handle != nullptr); + + typedef int (*int_fn)(void); + int_fn get_cxx_ctor_called, get_attr_ctor_called; + get_cxx_ctor_called = reinterpret_cast<int_fn>(dlsym(handle, "get_cxx_ctor_called")); + get_attr_ctor_called = reinterpret_cast<int_fn>(dlsym(handle, "get_attr_ctor_called")); + ASSERT_TRUE(get_cxx_ctor_called != nullptr); + ASSERT_TRUE(get_attr_ctor_called != nullptr); + + ASSERT_EQ(1, get_cxx_ctor_called()); + ASSERT_EQ(1, get_attr_ctor_called()); void* sym = dlsym(handle, "register_atexit"); - ASSERT_TRUE(sym != NULL); - reinterpret_cast<void (*)(std::string*, bool*)>(sym)(&atexit_call_sequence, &valid_this_in_static_dtor); + ASSERT_TRUE(sym != nullptr); + reinterpret_cast<void (*)(std::string*, bool*, bool*)>(sym)(&atexit_call_sequence, &valid_this_in_static_dtor, &attr_dtor_called); ASSERT_EQ(0, dlclose(handle)); // this test verifies atexit call from atexit handler. as well as the order of calls ASSERT_EQ("Humpty Dumpty sat on a wall", atexit_call_sequence); ASSERT_TRUE(valid_this_in_static_dtor); + ASSERT_TRUE(attr_dtor_called); } class TestMainStaticDtorClass { @@ -57,7 +70,7 @@ class TestMainStaticDtorClass { static const TestMainStaticDtorClass* expected_this; }; -const TestMainStaticDtorClass* TestMainStaticDtorClass::expected_this = NULL; +const TestMainStaticDtorClass* TestMainStaticDtorClass::expected_this = nullptr; static void atexit_func5() { fprintf(stderr, "5"); diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index da630463d..7bd59c84c 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -117,7 +117,7 @@ TEST_F(DlExtTest, Reserved) { ASSERT_DL_NOTNULL(handle_); fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); ASSERT_DL_NOTNULL(f); - EXPECT_GE(f, start); + EXPECT_GE(reinterpret_cast<void*>(f), start); EXPECT_LT(reinterpret_cast<void*>(f), reinterpret_cast<char*>(start) + LIBSIZE); EXPECT_EQ(4, f()); @@ -147,7 +147,7 @@ TEST_F(DlExtTest, ReservedHint) { ASSERT_DL_NOTNULL(handle_); fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); ASSERT_DL_NOTNULL(f); - EXPECT_GE(f, start); + EXPECT_GE(reinterpret_cast<void*>(f), start); EXPECT_LT(reinterpret_cast<void*>(f), reinterpret_cast<char*>(start) + LIBSIZE); EXPECT_EQ(4, f()); @@ -165,8 +165,9 @@ TEST_F(DlExtTest, ReservedHintTooSmall) { ASSERT_DL_NOTNULL(handle_); fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); ASSERT_DL_NOTNULL(f); - EXPECT_TRUE(f < start || (reinterpret_cast<void*>(f) >= - reinterpret_cast<char*>(start) + PAGE_SIZE)); + EXPECT_TRUE(reinterpret_cast<void*>(f) < start || + (reinterpret_cast<void*>(f) >= + reinterpret_cast<char*>(start) + PAGE_SIZE)); EXPECT_EQ(4, f()); } @@ -259,6 +260,11 @@ TEST_F(DlExtRelroSharingTest, RelroFileEmpty) { } TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) { + if (geteuid() != 0) { + GTEST_LOG_(INFO) << "This test must be run as root.\n"; + return; + } + ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME)); int relro_fd = open(relro_file_, O_RDONLY); ASSERT_NOERROR(relro_fd); diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index be0523018..6bdde4450 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -62,25 +62,6 @@ TEST(dlfcn, dlsym_in_self) { ASSERT_EQ(0, dlclose(self)); } -#if defined(__arm__) -// This seems to be working only for arm. -// Others platforms optimize LOCAL PROTECTED symbols. -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(1729U, f()); - dlclose(handle); -} -#endif - TEST(dlfcn, dlsym_with_dependencies) { void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW); ASSERT_TRUE(handle != NULL); @@ -109,32 +90,42 @@ TEST(dlfcn, dlopen_noload) { // ifuncs are only supported on intel for now #if defined(__i386__) || defined(__x86_64__) TEST(dlfcn, ifunc) { - const char* (*foo_ptr)(); - const char* (*foo_library_ptr)(); + typedef const char* (*fn_ptr)(); // ifunc's choice depends on whether IFUNC_CHOICE has a value // first check the set case setenv("IFUNC_CHOICE", "set", 1); void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); ASSERT_TRUE(handle != NULL); - *(void **)(&foo_ptr) = dlsym(handle, "foo"); - *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library"); + fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo")); + fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library")); ASSERT_TRUE(foo_ptr != NULL); ASSERT_TRUE(foo_library_ptr != NULL); - ASSERT_EQ(strncmp("set", (*foo_ptr)(), 3), 0); - ASSERT_EQ(strncmp("set", (*foo_library_ptr)(), 3), 0); + ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0); + ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0); dlclose(handle); // then check the unset case unsetenv("IFUNC_CHOICE"); handle = dlopen("libtest_ifunc.so", RTLD_NOW); ASSERT_TRUE(handle != NULL); - *(void **)(&foo_ptr) = dlsym(handle, "foo"); - *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library"); + foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo")); + foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library")); ASSERT_TRUE(foo_ptr != NULL); ASSERT_TRUE(foo_library_ptr != NULL); - ASSERT_EQ(strncmp("unset", (*foo_ptr)(), 5), 0); - ASSERT_EQ(strncmp("unset", (*foo_library_ptr)(), 3), 0); + ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0); + ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0); + dlclose(handle); +} + +TEST(dlfcn, ifunc_ctor_call) { + typedef const char* (*fn_ptr)(); + + void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); + ASSERT_TRUE(handle != NULL) << dlerror(); + fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called")); + ASSERT_TRUE(is_ctor_called != NULL) << dlerror(); + ASSERT_STREQ("true", is_ctor_called()); dlclose(handle); } #endif @@ -240,10 +231,8 @@ TEST(dlfcn, dladdr) { // Look in /proc/pid/maps to find out what address we were loaded at. // TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic. void* base_address = NULL; - char path[PATH_MAX]; - snprintf(path, sizeof(path), "/proc/%d/maps", getpid()); char line[BUFSIZ]; - FILE* fp = fopen(path, "r"); + FILE* fp = fopen("/proc/self/maps", "r"); ASSERT_TRUE(fp != NULL); while (fgets(line, sizeof(line), fp) != NULL) { uintptr_t start = strtoul(line, 0, 16); @@ -349,4 +338,6 @@ TEST(dlfcn, dlopen_symlink) { ASSERT_TRUE(handle1 != NULL); ASSERT_TRUE(handle2 != NULL); ASSERT_EQ(handle1, handle2); + dlclose(handle1); + dlclose(handle2); } diff --git a/tests/getauxval_test.cpp b/tests/getauxval_test.cpp index 51c9db84e..b33115007 100644 --- a/tests/getauxval_test.cpp +++ b/tests/getauxval_test.cpp @@ -15,7 +15,6 @@ */ #include <sys/cdefs.h> -#include <features.h> #include <gtest/gtest.h> // getauxval() was only added as of glibc version 2.16. diff --git a/tests/libc_logging_test.cpp b/tests/libc_logging_test.cpp index 950161e78..d4ceded45 100644 --- a/tests/libc_logging_test.cpp +++ b/tests/libc_logging_test.cpp @@ -176,3 +176,15 @@ TEST(libc_logging, lld_LLONG_MIN) { GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif // __BIONIC__ } + +TEST(libc_logging, buffer_overrun) { +#if defined(__BIONIC__) + char buf[BUFSIZ]; + ASSERT_EQ(11, __libc_format_buffer(buf, sizeof(buf), "hello %s", "world")); + EXPECT_STREQ("hello world", buf); + ASSERT_EQ(11, __libc_format_buffer(buf, 8, "hello %s", "world")); + EXPECT_STREQ("hello w", buf); +#else // __BIONIC__ + GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif // __BIONIC__ +} diff --git a/tests/libgen_test.cpp b/tests/libgen_test.cpp index cae646f25..d0402dbf6 100644 --- a/tests/libgen_test.cpp +++ b/tests/libgen_test.cpp @@ -14,11 +14,10 @@ * limitations under the License. */ -#include <gtest/gtest.h> - #include <libgen.h> #include <errno.h> +#include <gtest/gtest.h> static void TestBasename(const char* in, const char* expected_out) { char* writable_in = (in != NULL) ? strdup(in) : NULL; @@ -40,7 +39,7 @@ static void TestDirname(const char* in, const char* expected_out) { // Do not use basename as the test name, it's defined to another value in glibc // so leads to a differently named test on host versus target architectures. -TEST(libgen, basename_smoke) { +TEST(libgen, posix_basename) { TestBasename(NULL, "."); TestBasename("", "."); TestBasename("/usr/lib", "lib"); diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index bca2047e2..b1cc836c6 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -17,6 +17,7 @@ LOCAL_PATH := $(call my-dir) TEST_PATH := $(LOCAL_PATH)/.. +common_cppflags += -std=gnu++11 # ----------------------------------------------------------------------------- # Library used by dlfcn tests. # ----------------------------------------------------------------------------- @@ -129,21 +130,6 @@ ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) endif # ----------------------------------------------------------------------------- -# 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/atexit_testlib.cpp b/tests/libs/atexit_testlib.cpp index d35f57b74..314e8de26 100644 --- a/tests/libs/atexit_testlib.cpp +++ b/tests/libs/atexit_testlib.cpp @@ -19,12 +19,19 @@ #include <string> // use external control number from main test -static std::string* atexit_sequence = NULL; -static bool* atexit_valid_this_in_static_dtor = NULL; +static std::string* atexit_sequence = nullptr; +static bool* atexit_valid_this_in_static_dtor = nullptr; +static bool* atexit_attr_dtor_called = nullptr; + +static int cxx_ctor_called = 0; +static int attr_ctor_called = 0; static class AtExitStaticClass { public: - AtExitStaticClass() { expected_this = this; } + AtExitStaticClass() { + expected_this = this; + cxx_ctor_called = 1; + } ~AtExitStaticClass() { if (atexit_valid_this_in_static_dtor) { *atexit_valid_this_in_static_dtor = (expected_this == this); @@ -35,7 +42,7 @@ static class AtExitStaticClass { } static_obj; -const AtExitStaticClass* AtExitStaticClass::expected_this = NULL; +const AtExitStaticClass* AtExitStaticClass::expected_this = nullptr; // 4 static void atexit_handler_from_atexit_from_atexit2() { @@ -66,10 +73,30 @@ static void atexit_handler_regular() { *atexit_sequence += " a wall"; } -extern "C" void register_atexit(std::string* sequence, bool* valid_this_in_static_dtor) { +// attribute c-tor and d-tor +static void __attribute__((constructor)) atexit_attr_ctor() { + attr_ctor_called = 1; +} + +static void __attribute__((destructor)) atexit_attr_dtor() { + if (atexit_attr_dtor_called) { + *atexit_attr_dtor_called = true; + } +} + +extern "C" void register_atexit(std::string* sequence, bool* valid_this_in_static_dtor, bool* attr_dtor_called) { atexit_sequence = sequence; atexit_valid_this_in_static_dtor = valid_this_in_static_dtor; + atexit_attr_dtor_called = attr_dtor_called; atexit(atexit_handler_regular); atexit(atexit_handler_with_atexit); } +extern "C" int get_cxx_ctor_called() { + return cxx_ctor_called; +} + +extern "C" int get_attr_ctor_called() { + return attr_ctor_called; +} + diff --git a/tests/libs/dlopen_testlib_ifunc.c b/tests/libs/dlopen_testlib_ifunc.c index 1c4baface..48748417d 100644 --- a/tests/libs/dlopen_testlib_ifunc.c +++ b/tests/libs/dlopen_testlib_ifunc.c @@ -17,7 +17,22 @@ #include <stdio.h> #include <stdlib.h> +static int g_flag = 0; + +static void __attribute__((constructor)) init_flag() { + g_flag = 1; +} + const char* foo() __attribute__ ((ifunc ("foo_ifunc"))); +const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun"))); + +const char* return_true() { + return "true"; +} + +const char* return_false() { + return "false"; +} const char* f1() { return "unset"; @@ -27,6 +42,10 @@ const char* f2() { return "set"; } +void* is_ctor_called_ifun() { + return g_flag == 0 ? return_false : return_true; +} + void* foo_ifunc() { char* choice = getenv("IFUNC_CHOICE"); return choice == NULL ? f1 : f2; @@ -34,4 +53,4 @@ void* foo_ifunc() { const char* foo_library() { return foo(); -}
\ No newline at end of file +} diff --git a/tests/libs/dlsym_local_symbol_public.cpp b/tests/libs/dlsym_local_symbol_public.cpp deleted file mode 100644 index d9da32a59..000000000 --- a/tests/libs/dlsym_local_symbol_public.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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/locale_test.cpp b/tests/locale_test.cpp index 325f6ceda..7ec607a28 100644 --- a/tests/locale_test.cpp +++ b/tests/locale_test.cpp @@ -114,11 +114,12 @@ TEST(locale, mb_cur_max) { locale_t cloc = newlocale(LC_ALL, "C", 0); locale_t cloc_utf8 = newlocale(LC_ALL, "C.UTF-8", 0); - uselocale(cloc); + locale_t old_locale = uselocale(cloc); ASSERT_EQ(1U, MB_CUR_MAX); uselocale(cloc_utf8); ASSERT_EQ(4U, MB_CUR_MAX); + uselocale(old_locale); freelocale(cloc); freelocale(cloc_utf8); } diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp index 6b7a28b1c..b76625a7a 100644 --- a/tests/malloc_test.cpp +++ b/tests/malloc_test.cpp @@ -22,6 +22,8 @@ #include <malloc.h> #include <unistd.h> +#include <tinyxml2.h> + #include "private/bionic_config.h" TEST(malloc, malloc_std) { @@ -322,3 +324,51 @@ TEST(malloc, valloc_overflow) { ASSERT_EQ(NULL, valloc(SIZE_MAX)); } #endif + +TEST(malloc, malloc_info) { +#ifdef __BIONIC__ + char* buf; + size_t bufsize; + FILE* memstream = open_memstream(&buf, &bufsize); + ASSERT_NE(nullptr, memstream); + ASSERT_EQ(0, malloc_info(0, memstream)); + ASSERT_EQ(0, fclose(memstream)); + + tinyxml2::XMLDocument doc; + ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buf)); + + auto root = doc.FirstChildElement(); + ASSERT_NE(nullptr, root); + ASSERT_STREQ("malloc", root->Name()); + ASSERT_STREQ("jemalloc-1", root->Attribute("version")); + + auto arena = root->FirstChildElement(); + for (; arena != nullptr; arena = arena->NextSiblingElement()) { + int val; + + ASSERT_STREQ("heap", arena->Name()); + ASSERT_EQ(tinyxml2::XML_SUCCESS, arena->QueryIntAttribute("nr", &val)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, + arena->FirstChildElement("allocated-large")->QueryIntText(&val)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, + arena->FirstChildElement("allocated-huge")->QueryIntText(&val)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, + arena->FirstChildElement("allocated-bins")->QueryIntText(&val)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, + arena->FirstChildElement("bins-total")->QueryIntText(&val)); + + auto bin = arena->FirstChildElement("bin"); + for (; bin != nullptr; bin = bin ->NextSiblingElement()) { + if (strcmp(bin->Name(), "bin") == 0) { + ASSERT_EQ(tinyxml2::XML_SUCCESS, bin->QueryIntAttribute("nr", &val)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, + bin->FirstChildElement("allocated")->QueryIntText(&val)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, + bin->FirstChildElement("nmalloc")->QueryIntText(&val)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, + bin->FirstChildElement("ndalloc")->QueryIntText(&val)); + } + } + } +#endif +} diff --git a/tests/math_cos_test.cpp b/tests/math_cos_test.cpp index c0a2d82c7..4917e87fa 100644 --- a/tests/math_cos_test.cpp +++ b/tests/math_cos_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -5634,6 +5636,7 @@ static cos_intel_data_t g_cos_intel_data[] = { TEST(math_cos, cos_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_cos_intel_data)/sizeof(cos_intel_data_t); i++) { EXPECT_DOUBLE_EQ(g_cos_intel_data[i].expected, cos(g_cos_intel_data[i].call_data)) << "Failed on element " << i; } diff --git a/tests/math_cosf_test.cpp b/tests/math_cosf_test.cpp index ea95ff317..8520c1dcc 100644 --- a/tests/math_cosf_test.cpp +++ b/tests/math_cosf_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -4346,6 +4348,7 @@ static cosf_intel_data_t g_cosf_intel_data[] = { TEST(math_cosf, cosf_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_cosf_intel_data)/sizeof(cosf_intel_data_t); i++) { EXPECT_FLOAT_EQ(g_cosf_intel_data[i].expected, cosf(g_cosf_intel_data[i].call_data)) << "Failed on element " << i; } diff --git a/tests/math_exp_test.cpp b/tests/math_exp_test.cpp index beb258497..c9c6ad594 100644 --- a/tests/math_exp_test.cpp +++ b/tests/math_exp_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -1966,6 +1968,7 @@ static exp_intel_data_t g_exp_intel_data[] = { TEST(math_exp, exp_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_exp_intel_data)/sizeof(exp_intel_data_t); i++) { EXPECT_DOUBLE_EQ(g_exp_intel_data[i].expected, exp(g_exp_intel_data[i].call_data)) << "Failed on element " << i; } diff --git a/tests/math_expf_test.cpp b/tests/math_expf_test.cpp index 257aa26bb..30bc94690 100644 --- a/tests/math_expf_test.cpp +++ b/tests/math_expf_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -1430,6 +1432,7 @@ static expf_intel_data_t g_expf_intel_data[] = { TEST(math_expf, expf_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_expf_intel_data)/sizeof(expf_intel_data_t); i++) { EXPECT_FLOAT_EQ(g_expf_intel_data[i].expected, expf(g_expf_intel_data[i].call_data)) << "Failed on element " << i; } diff --git a/tests/math_log_test.cpp b/tests/math_log_test.cpp index da2a848e4..4f136a774 100644 --- a/tests/math_log_test.cpp +++ b/tests/math_log_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -1666,6 +1668,7 @@ static log_intel_data_t g_log_intel_data[] = { TEST(math_log, log_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_log_intel_data)/sizeof(log_intel_data_t); i++) { EXPECT_DOUBLE_EQ(g_log_intel_data[i].expected, log(g_log_intel_data[i].call_data)) << "Failed on element " << i; } diff --git a/tests/math_logf_test.cpp b/tests/math_logf_test.cpp index e5d0921d8..ca02095c1 100644 --- a/tests/math_logf_test.cpp +++ b/tests/math_logf_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -1318,6 +1320,7 @@ static logf_intel_data_t g_logf_intel_data[] = { TEST(math_logf, logf_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_logf_intel_data)/sizeof(logf_intel_data_t); i++) { EXPECT_FLOAT_EQ(g_logf_intel_data[i].expected, logf(g_logf_intel_data[i].call_data)) << "Failed on element " << i; } diff --git a/tests/math_pow_test.cpp b/tests/math_pow_test.cpp index c185424c7..a4caa36cc 100644 --- a/tests/math_pow_test.cpp +++ b/tests/math_pow_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -3291,6 +3293,7 @@ static pow_intel_data_t g_pow_intel_data[] = { TEST(math_pow, pow_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_pow_intel_data)/sizeof(pow_intel_data_t); i++) { EXPECT_DOUBLE_EQ(g_pow_intel_data[i].expected, pow(g_pow_intel_data[i].x_call_data, g_pow_intel_data[i].y_call_data)) << "Failed on element " << i; } diff --git a/tests/math_powf_test.cpp b/tests/math_powf_test.cpp index f77b23a4b..72726447f 100644 --- a/tests/math_powf_test.cpp +++ b/tests/math_powf_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -2779,6 +2781,7 @@ static powf_intel_data_t g_powf_intel_data[] = { TEST(math_powf, powf_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_powf_intel_data)/sizeof(powf_intel_data_t); i++) { EXPECT_FLOAT_EQ(g_powf_intel_data[i].expected, powf(g_powf_intel_data[i].x_call_data, g_powf_intel_data[i].y_call_data)) << "Failed on element " << i; } diff --git a/tests/math_sin_test.cpp b/tests/math_sin_test.cpp index ffa43409d..509642ca8 100644 --- a/tests/math_sin_test.cpp +++ b/tests/math_sin_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -5786,6 +5788,7 @@ static sin_intel_data_t g_sin_intel_data[] = { TEST(math_sin, sin_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_sin_intel_data)/sizeof(sin_intel_data_t); i++) { EXPECT_DOUBLE_EQ(g_sin_intel_data[i].expected, sin(g_sin_intel_data[i].call_data)) << "Failed on element " << i; } diff --git a/tests/math_sincos_test.cpp b/tests/math_sincos_test.cpp index 0fab2c20f..4093fb9df 100644 --- a/tests/math_sincos_test.cpp +++ b/tests/math_sincos_test.cpp @@ -14,8 +14,12 @@ * limitations under the License. */ +#define _GNU_SOURCE 1 + #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -4776,6 +4780,7 @@ static sincos_intel_data_t g_sincos_intel_data[] = { TEST(math_sincos, sincos_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_sincos_intel_data)/sizeof(sincos_intel_data_t); i++) { double dsin, dcos; sincos(g_sincos_intel_data[i].call_data, &dsin, &dcos); diff --git a/tests/math_sincosf_test.cpp b/tests/math_sincosf_test.cpp index c1a32c9e0..d30f72e90 100644 --- a/tests/math_sincosf_test.cpp +++ b/tests/math_sincosf_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -4646,6 +4648,7 @@ static sincosf_intel_data_t g_sincosf_intel_data[] = { TEST(math_sincosf, sincosf_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_sincosf_intel_data)/sizeof(sincosf_intel_data_t); i++) { float fsin, fcos; sincosf(g_sincosf_intel_data[i].call_data, &fsin, &fcos); diff --git a/tests/math_sinf_test.cpp b/tests/math_sinf_test.cpp index bb1e2c953..0c2e6f172 100644 --- a/tests/math_sinf_test.cpp +++ b/tests/math_sinf_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -4386,6 +4388,7 @@ static sinf_intel_data_t g_sinf_intel_data[] = { TEST(math_sinf, sinf_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_sinf_intel_data)/sizeof(sinf_intel_data_t); i++) { EXPECT_FLOAT_EQ(g_sinf_intel_data[i].expected, sinf(g_sinf_intel_data[i].call_data)) << "Failed on element " << i; } diff --git a/tests/math_tan_test.cpp b/tests/math_tan_test.cpp index 68620194a..e555ef3c9 100644 --- a/tests/math_tan_test.cpp +++ b/tests/math_tan_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -5194,6 +5196,7 @@ static tan_intel_data_t g_tan_intel_data[] = { TEST(math_tan, tan_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_tan_intel_data)/sizeof(tan_intel_data_t); i++) { EXPECT_DOUBLE_EQ(g_tan_intel_data[i].expected, tan(g_tan_intel_data[i].call_data)) << "Failed on element " << i; } diff --git a/tests/math_tanf_test.cpp b/tests/math_tanf_test.cpp index 9319046cb..db04116b5 100644 --- a/tests/math_tanf_test.cpp +++ b/tests/math_tanf_test.cpp @@ -16,6 +16,8 @@ #include <math.h> +#include <fenv.h> + #include <gtest/gtest.h> #if defined(__BIONIC__) @@ -4450,6 +4452,7 @@ static tanf_intel_data_t g_tanf_intel_data[] = { TEST(math_tanf, tanf_intel) { #if defined(__BIONIC__) + fesetenv(FE_DFL_ENV); for (size_t i = 0; i < sizeof(g_tanf_intel_data)/sizeof(tanf_intel_data_t); i++) { EXPECT_FLOAT_EQ(g_tanf_intel_data[i].expected, tanf(g_tanf_intel_data[i].call_data)) << "Failed on element " << i; } diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp index 5328e48cf..bbac7fe95 100644 --- a/tests/pthread_test.cpp +++ b/tests/pthread_test.cpp @@ -23,6 +23,7 @@ #include <pthread.h> #include <signal.h> #include <sys/mman.h> +#include <sys/syscall.h> #include <time.h> #include <unistd.h> @@ -104,6 +105,7 @@ TEST(pthread, pthread_key_fork) { ASSERT_EQ(99, WEXITSTATUS(status)); ASSERT_EQ(expected, pthread_getspecific(key)); + ASSERT_EQ(0, pthread_key_delete(key)); } static void* DirtyKeyFn(void* key) { @@ -131,6 +133,7 @@ TEST(pthread, pthread_key_dirty) { ASSERT_EQ(nullptr, result); // Not ~0! ASSERT_EQ(0, munmap(stack, stack_size)); + ASSERT_EQ(0, pthread_key_delete(key)); } static void* IdFn(void* arg) { @@ -816,3 +819,81 @@ TEST(pthread, pthread_mutex_timedlock) { ASSERT_EQ(0, pthread_mutex_unlock(&m)); ASSERT_EQ(0, pthread_mutex_destroy(&m)); } + +TEST(pthread, pthread_attr_getstack__main_thread) { + // This test is only meaningful for the main thread, so make sure we're running on it! + ASSERT_EQ(getpid(), syscall(__NR_gettid)); + + // Get the main thread's attributes. + pthread_attr_t attributes; + ASSERT_EQ(0, pthread_getattr_np(pthread_self(), &attributes)); + + // Check that we correctly report that the main thread has no guard page. + size_t guard_size; + ASSERT_EQ(0, pthread_attr_getguardsize(&attributes, &guard_size)); + ASSERT_EQ(0U, guard_size); // The main thread has no guard page. + + // Get the stack base and the stack size (both ways). + void* stack_base; + size_t stack_size; + ASSERT_EQ(0, pthread_attr_getstack(&attributes, &stack_base, &stack_size)); + size_t stack_size2; + ASSERT_EQ(0, pthread_attr_getstacksize(&attributes, &stack_size2)); + + // The two methods of asking for the stack size should agree. + EXPECT_EQ(stack_size, stack_size2); + + // What does /proc/self/maps' [stack] line say? + void* maps_stack_hi = NULL; + FILE* fp = fopen("/proc/self/maps", "r"); + ASSERT_TRUE(fp != NULL); + char line[BUFSIZ]; + while (fgets(line, sizeof(line), fp) != NULL) { + uintptr_t lo, hi; + char name[10]; + sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d %10s", &lo, &hi, name); + if (strcmp(name, "[stack]") == 0) { + maps_stack_hi = reinterpret_cast<void*>(hi); + break; + } + } + fclose(fp); + + // The stack size should correspond to RLIMIT_STACK. + rlimit rl; + ASSERT_EQ(0, getrlimit(RLIMIT_STACK, &rl)); + EXPECT_EQ(rl.rlim_cur, stack_size); + + // The high address of the /proc/self/maps [stack] region should equal stack_base + stack_size. + // Remember that the stack grows down (and is mapped in on demand), so the low address of the + // region isn't very interesting. + EXPECT_EQ(maps_stack_hi, reinterpret_cast<uint8_t*>(stack_base) + stack_size); + + // + // What if RLIMIT_STACK is smaller than the stack's current extent? + // + rl.rlim_cur = rl.rlim_max = 1024; // 1KiB. We know the stack must be at least a page already. + rl.rlim_max = RLIM_INFINITY; + ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl)); + + ASSERT_EQ(0, pthread_getattr_np(pthread_self(), &attributes)); + ASSERT_EQ(0, pthread_attr_getstack(&attributes, &stack_base, &stack_size)); + ASSERT_EQ(0, pthread_attr_getstacksize(&attributes, &stack_size2)); + + EXPECT_EQ(stack_size, stack_size2); + ASSERT_EQ(1024U, stack_size); + + // + // What if RLIMIT_STACK isn't a whole number of pages? + // + rl.rlim_cur = rl.rlim_max = 6666; // Not a whole number of pages. + rl.rlim_max = RLIM_INFINITY; + ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl)); + + ASSERT_EQ(0, pthread_getattr_np(pthread_self(), &attributes)); + ASSERT_EQ(0, pthread_attr_getstack(&attributes, &stack_base, &stack_size)); + ASSERT_EQ(0, pthread_attr_getstacksize(&attributes, &stack_size2)); + + EXPECT_EQ(stack_size, stack_size2); + ASSERT_EQ(6666U, stack_size); +} diff --git a/tests/stdatomic_test.cpp b/tests/stdatomic_test.cpp index 5e88c8801..b7fb19b0d 100644 --- a/tests/stdatomic_test.cpp +++ b/tests/stdatomic_test.cpp @@ -14,11 +14,10 @@ * limitations under the License. */ -#include <gtest/gtest.h> - -#if !defined(__GLIBC__) /* TODO: fix our prebuilt toolchains! */ - #include <stdatomic.h> +#include <gtest/gtest.h> +#include <pthread.h> +#include <stdint.h> TEST(stdatomic, LOCK_FREE) { ASSERT_TRUE(ATOMIC_BOOL_LOCK_FREE); @@ -64,14 +63,17 @@ TEST(stdatomic, atomic_signal_fence) { TEST(stdatomic, atomic_is_lock_free) { atomic_char small; - atomic_intmax_t big; ASSERT_TRUE(atomic_is_lock_free(&small)); +#if defined(__clang__) || __GNUC_PREREQ(4, 7) + // Otherwise stdatomic.h doesn't handle this. + atomic_intmax_t big; // atomic_intmax_t(size = 64) is not lock free on mips32. #if defined(__mips__) && !defined(__LP64__) ASSERT_FALSE(atomic_is_lock_free(&big)); #else ASSERT_TRUE(atomic_is_lock_free(&big)); #endif +#endif } TEST(stdatomic, atomic_flag) { @@ -167,4 +169,80 @@ TEST(stdatomic, atomic_fetch_and) { ASSERT_EQ(0x002, atomic_load(&i)); } -#endif +// And a rudimentary test of acquire-release memory ordering: + +constexpr static uint_least32_t BIG = 10000000ul; // Assumed even below. + +struct three_atomics { + atomic_uint_least32_t x; + char a[123]; // Everything in different cache lines, + // increase chance of compiler getting alignment wrong. + atomic_uint_least32_t y; + char b[4013]; + atomic_uint_least32_t z; +}; + +// Very simple acquire/release memory ordering sanity check. +static void* writer(void* arg) { + three_atomics* a = reinterpret_cast<three_atomics*>(arg); + for (uint_least32_t i = 0; i <= BIG; i+=2) { + atomic_store_explicit(&a->x, i, memory_order_relaxed); + atomic_store_explicit(&a->z, i, memory_order_relaxed); + atomic_store_explicit(&a->y, i, memory_order_release); + atomic_store_explicit(&a->x, i+1, memory_order_relaxed); + atomic_store_explicit(&a->z, i+1, memory_order_relaxed); + atomic_store_explicit(&a->y, i+1, memory_order_release); + } + return 0; +} + +static void* reader(void* arg) { + three_atomics* a = reinterpret_cast<three_atomics*>(arg); + uint_least32_t xval = 0, yval = 0, zval = 0; + size_t repeat = 0; + size_t repeat_limit = 1000; + while (yval != BIG + 1) { + yval = atomic_load_explicit(&a->y, memory_order_acquire); + zval = atomic_load_explicit(&a->z, memory_order_relaxed); + xval = atomic_load_explicit(&a->x, memory_order_relaxed); + // If we see a given value of y, the immediately preceding + // stores to z and x, or later ones, should also be visible. + if (zval < yval) { + // Cant just ASSERT, since we are in a non-void function. + ADD_FAILURE() << "acquire-release ordering violation: " + << zval << " < " << yval << ", " << xval << "\n"; + return 0; // Only report once. + } + if (xval < yval) { + // Cant just ASSERT, since we are in a non-void function. + ADD_FAILURE() << "acquire-release ordering violation: " + << xval << " < " << yval << ", " << zval << "\n"; + return 0; // Only report once. + } + if (repeat < repeat_limit) ++repeat; + } + // The following assertion is not technically guaranteed to hold. + // But if it fails to hold, this test was useless, and we have a + // serious scheduling issue that we should probably know about. + EXPECT_EQ(repeat, repeat_limit); + return 0; +} + +TEST(stdatomic, ordering) { + // Run a memory ordering sanity test. + void* result; + three_atomics a; + atomic_init(&a.x, 0ul); + atomic_init(&a.y, 0ul); + atomic_init(&a.z, 0ul); + pthread_t t1,t2; + ASSERT_EQ(0, pthread_create(&t1, 0, reader, &a)); + ASSERT_EQ(0, pthread_create(&t2, 0, writer, &a)); + ASSERT_EQ(0, pthread_join(t1, &result)); + EXPECT_EQ(0, result); + ASSERT_EQ(0, pthread_join(t2, &result)); + EXPECT_EQ(0, result); + EXPECT_EQ(atomic_load_explicit(&a.x, memory_order_consume), BIG + 1); + EXPECT_EQ(atomic_load_explicit(&a.y, memory_order_seq_cst), BIG + 1); + EXPECT_EQ(atomic_load(&a.z), BIG + 1); +} diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp new file mode 100644 index 000000000..3dbc485a6 --- /dev/null +++ b/tests/stdio_ext_test.cpp @@ -0,0 +1,133 @@ +/* + * 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 <stdio_ext.h> + +#include <gtest/gtest.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <math.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <wchar.h> +#include <locale.h> + +#include "TemporaryFile.h" + +TEST(stdio_ext, __fbufsize) { + FILE* fp = fopen("/proc/version", "r"); + + char buf[128]; + + ASSERT_EQ(0, setvbuf(fp, buf, _IOFBF, 1)); + ASSERT_EQ(1U, __fbufsize(fp)); + + ASSERT_EQ(0, setvbuf(fp, buf, _IOFBF, 8)); + ASSERT_EQ(8U, __fbufsize(fp)); + + fclose(fp); +} + +TEST(stdio_ext, __flbf) { + FILE* fp = fopen("/proc/version", "r"); + + ASSERT_FALSE(__flbf(fp)); + + char buf[128]; + ASSERT_EQ(0, setvbuf(fp, buf, _IOLBF, sizeof(buf))); + + ASSERT_TRUE(__flbf(fp)); + + fclose(fp); +} + +TEST(stdio_ext, __fpending) { + FILE* fp = fopen("/dev/null", "w"); + ASSERT_EQ(0U, __fpending(fp)); + ASSERT_EQ('x', fputc('x', fp)); + ASSERT_EQ(1U, __fpending(fp)); + ASSERT_EQ('y', fputc('y', fp)); + ASSERT_EQ(2U, __fpending(fp)); + fflush(fp); + ASSERT_EQ(0U, __fpending(fp)); + fclose(fp); +} + +TEST(stdio_ext, __fpurge) { + FILE* fp = tmpfile(); + + ASSERT_EQ('a', fputc('a', fp)); + ASSERT_EQ(1U, __fpending(fp)); + __fpurge(fp); + ASSERT_EQ(0U, __fpending(fp)); + + ASSERT_EQ('b', fputc('b', fp)); + ASSERT_EQ('\n', fputc('\n', fp)); + ASSERT_EQ(2U, __fpending(fp)); + + rewind(fp); + + char buf[16]; + char* s = fgets(buf, sizeof(buf), fp); + ASSERT_TRUE(s != NULL); + ASSERT_STREQ("b\n", s); + + fclose(fp); +} + +TEST(stdio_ext, _flushlbf) { + FILE* fp = fopen("/dev/null", "w"); + + char buf[128]; + ASSERT_EQ(0, setvbuf(fp, buf, _IOLBF, sizeof(buf))); + + ASSERT_EQ('a', fputc('a', fp)); + ASSERT_EQ(1U, __fpending(fp)); + + _flushlbf(); + + ASSERT_EQ(0U, __fpending(fp)); + + fclose(fp); +} + +TEST(stdio_ext, __freadable__fwritable) { + FILE* fp = fopen("/dev/null", "r"); + ASSERT_TRUE(__freadable(fp)); + ASSERT_FALSE(__fwritable(fp)); + fclose(fp); + + fp = fopen("/dev/null", "w"); + ASSERT_FALSE(__freadable(fp)); + ASSERT_TRUE(__fwritable(fp)); + fclose(fp); + + fp = fopen("/dev/null", "w+"); + ASSERT_TRUE(__freadable(fp)); + ASSERT_TRUE(__fwritable(fp)); + fclose(fp); +} + +TEST(stdio_ext, __fsetlocking) { + FILE* fp = fopen("/proc/version", "r"); + // Android doesn't actually support the other modes. + ASSERT_EQ(FSETLOCKING_INTERNAL, __fsetlocking(fp, FSETLOCKING_QUERY)); + fclose(fp); +} diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index bb86509c2..c01ab683c 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -428,7 +428,7 @@ TEST(stdio, snprintf_negative_zero_5084292) { TEST(stdio, snprintf_utf8_15439554) { locale_t cloc = newlocale(LC_ALL, "C.UTF-8", 0); - uselocale(cloc); + locale_t old_locale = uselocale(cloc); // http://b/15439554 char buf[BUFSIZ]; @@ -446,6 +446,7 @@ TEST(stdio, snprintf_utf8_15439554) { snprintf(buf, sizeof(buf), "%d\xf0\xa4\xad\xa2%d", 1, 2); EXPECT_STREQ("1𤭢2", buf); + uselocale(old_locale); freelocale(cloc); } @@ -676,3 +677,82 @@ TEST(stdio, fpos_t_and_seek) { fclose(fp); } + +TEST(stdio, fmemopen) { + char buf[16]; + memset(buf, 0, sizeof(buf)); + FILE* fp = fmemopen(buf, sizeof(buf), "r+"); + ASSERT_EQ('<', fputc('<', fp)); + ASSERT_NE(EOF, fputs("abc>\n", fp)); + fflush(fp); + + ASSERT_STREQ("<abc>\n", buf); + + rewind(fp); + + char line[16]; + char* s = fgets(line, sizeof(line), fp); + ASSERT_TRUE(s != NULL); + ASSERT_STREQ("<abc>\n", s); + + fclose(fp); +} + +TEST(stdio, fmemopen_NULL) { + FILE* fp = fmemopen(nullptr, 128, "r+"); + ASSERT_NE(EOF, fputs("xyz\n", fp)); + + rewind(fp); + + char line[16]; + char* s = fgets(line, sizeof(line), fp); + ASSERT_TRUE(s != NULL); + ASSERT_STREQ("xyz\n", s); + + fclose(fp); +} + +TEST(stdio, fmemopen_EINVAL) { + char buf[16]; + + // Invalid size. + errno = 0; + ASSERT_EQ(nullptr, fmemopen(buf, 0, "r+")); + ASSERT_EQ(EINVAL, errno); + + // No '+' with NULL buffer. + errno = 0; + ASSERT_EQ(nullptr, fmemopen(nullptr, 0, "r")); + ASSERT_EQ(EINVAL, errno); +} + +TEST(stdio, open_memstream) { + char* p = nullptr; + size_t size = 0; + FILE* fp = open_memstream(&p, &size); + ASSERT_NE(EOF, fputs("hello, world!", fp)); + fclose(fp); + + ASSERT_STREQ("hello, world!", p); + ASSERT_EQ(strlen("hello, world!"), size); + free(p); +} + +TEST(stdio, open_memstream_EINVAL) { +#if defined(__BIONIC__) + char* p; + size_t size; + + // Invalid buffer. + errno = 0; + ASSERT_EQ(nullptr, open_memstream(nullptr, &size)); + ASSERT_EQ(EINVAL, errno); + + // Invalid size. + errno = 0; + ASSERT_EQ(nullptr, open_memstream(&p, nullptr)); + ASSERT_EQ(EINVAL, errno); +#else + GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif +} diff --git a/tests/string_posix_strerror_r_test.cpp b/tests/string_posix_strerror_r_test.cpp new file mode 100644 index 000000000..09cebfecc --- /dev/null +++ b/tests/string_posix_strerror_r_test.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 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. + */ + +#undef _GNU_SOURCE + +// Old versions of glibc (like our current host prebuilt sysroot one) have +// headers that don't work if you #undef _GNU_SOURCE, which makes it +// impossible to build this test. +#include <features.h> + +#if !defined(__GLIBC__) +#include <string.h> + +#include <errno.h> +#include <gtest/gtest.h> + +TEST(string, posix_strerror_r) { + char buf[256]; + + // Valid. + ASSERT_EQ(0, strerror_r(0, buf, sizeof(buf))); + ASSERT_STREQ("Success", buf); + ASSERT_EQ(0, strerror_r(1, buf, sizeof(buf))); + ASSERT_STREQ("Operation not permitted", buf); + + // Invalid. + ASSERT_EQ(0, strerror_r(-1, buf, sizeof(buf))); + ASSERT_STREQ("Unknown error -1", buf); + ASSERT_EQ(0, strerror_r(1234, buf, sizeof(buf))); + ASSERT_STREQ("Unknown error 1234", buf); + + // Buffer too small. + errno = 0; + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(-1, strerror_r(4567, buf, 2)); + ASSERT_STREQ("U", buf); + // The POSIX strerror_r sets errno to ERANGE (the GNU one doesn't). + ASSERT_EQ(ERANGE, errno); +} +#else +# if __GLIBC_PREREQ(2, 15) +# error this test should work now +# endif +#endif diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 8ec2928cc..ad0040aa9 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -14,12 +14,14 @@ * limitations under the License. */ -#include <gtest/gtest.h> +#define _GNU_SOURCE 1 + +#include <string.h> #include <errno.h> +#include <gtest/gtest.h> #include <malloc.h> #include <math.h> -#include <string.h> #include "buffer_tests.h" @@ -72,28 +74,34 @@ TEST(string, strerror_concurrent) { #endif // __BIONIC__ } -TEST(string, strerror_r) { -#if defined(__BIONIC__) // glibc's strerror_r doesn't even have the same signature as the POSIX one. +TEST(string, gnu_strerror_r) { char buf[256]; + // Note that glibc doesn't necessarily write into the buffer. + // Valid. - ASSERT_EQ(0, strerror_r(0, buf, sizeof(buf))); + ASSERT_STREQ("Success", strerror_r(0, buf, sizeof(buf))); +#if defined(__BIONIC__) ASSERT_STREQ("Success", buf); - ASSERT_EQ(0, strerror_r(1, buf, sizeof(buf))); +#endif + ASSERT_STREQ("Operation not permitted", strerror_r(1, buf, sizeof(buf))); +#if defined(__BIONIC__) ASSERT_STREQ("Operation not permitted", buf); +#endif // Invalid. - ASSERT_EQ(0, strerror_r(-1, buf, sizeof(buf))); + ASSERT_STREQ("Unknown error -1", strerror_r(-1, buf, sizeof(buf))); ASSERT_STREQ("Unknown error -1", buf); - ASSERT_EQ(0, strerror_r(1234, buf, sizeof(buf))); + ASSERT_STREQ("Unknown error 1234", strerror_r(1234, buf, sizeof(buf))); ASSERT_STREQ("Unknown error 1234", buf); // Buffer too small. - ASSERT_EQ(-1, strerror_r(0, buf, 2)); - ASSERT_EQ(ERANGE, errno); -#else // __BIONIC__ - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif // __BIONIC__ + errno = 0; + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(buf, strerror_r(4567, buf, 2)); + ASSERT_STREQ("U", buf); + // The GNU strerror_r doesn't set errno (the POSIX one sets it to ERANGE). + ASSERT_EQ(0, errno); } TEST(string, strsignal) { @@ -1274,3 +1282,22 @@ TEST(string, strchr_align) { TEST(string, strchr_overread) { RunSingleBufferOverreadTest(DoStrchrTest); } + +static void TestBasename(const char* in, const char* expected_out) { + errno = 0; + const char* out = basename(in); + ASSERT_STREQ(expected_out, out) << in; + ASSERT_EQ(0, errno) << in; +} + +TEST(string, __gnu_basename) { + TestBasename("", ""); + TestBasename("/usr/lib", "lib"); + TestBasename("/usr/", ""); + TestBasename("usr", "usr"); + TestBasename("/", ""); + TestBasename(".", "."); + TestBasename("..", ".."); + TestBasename("///", ""); + TestBasename("//usr//lib//", ""); +} diff --git a/tests/sys_socket_test.cpp b/tests/sys_socket_test.cpp index 0bde0243d..38ef68a99 100644 --- a/tests/sys_socket_test.cpp +++ b/tests/sys_socket_test.cpp @@ -23,13 +23,9 @@ #include <fcntl.h> #if defined(__BIONIC__) - #define ACCEPT4_SUPPORTED 1 #define RECVMMSG_SUPPORTED 1 #define SENDMMSG_SUPPORTED 1 #elif defined(__GLIBC_PREREQ) - #if __GLIBC_PREREQ(2, 9) - #define ACCEPT4_SUPPORTED 1 - #endif #if __GLIBC_PREREQ(2, 12) #define RECVMMSG_SUPPORTED 1 #endif @@ -38,8 +34,6 @@ #endif #endif -#if defined(ACCEPT4_SUPPORTED) || defined(RECVMMSG_SUPPORTED) || defined(SENDMMSG_SUPPORTED) - #define SOCK_PATH "test" static void* ConnectFn(void* data) { @@ -105,18 +99,12 @@ static void RunTest(void (*test_fn)(struct sockaddr_un*, int), close(fd); } -#endif TEST(sys_socket, accept4_error) { -#if defined(ACCEPT4_SUPPORTED) ASSERT_EQ(-1, accept4(-1, NULL, NULL, 0)); ASSERT_EQ(EBADF, errno); -#else - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif } -#if defined(ACCEPT4_SUPPORTED) static void TestAccept4(struct sockaddr_un* addr, int fd) { socklen_t len = sizeof(*addr); int fd_acc = accept4(fd, reinterpret_cast<struct sockaddr*>(addr), &len, SOCK_CLOEXEC); @@ -127,14 +115,9 @@ static void TestAccept4(struct sockaddr_un* addr, int fd) { close(fd_acc); } -#endif TEST(sys_socket, accept4_smoke) { -#if defined(ACCEPT4_SUPPORTED) RunTest(TestAccept4, NULL); -#else - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif } #if defined(RECVMMSG_SUPPORTED) diff --git a/tests/time_test.cpp b/tests/time_test.cpp index 241c4a0c4..c9ead8dbb 100644 --- a/tests/time_test.cpp +++ b/tests/time_test.cpp @@ -17,7 +17,6 @@ #include <time.h> #include <errno.h> -#include <features.h> #include <gtest/gtest.h> #include <pthread.h> #include <signal.h> diff --git a/tests/uchar_test.cpp b/tests/uchar_test.cpp index eca3c5ea4..c887f8abd 100644 --- a/tests/uchar_test.cpp +++ b/tests/uchar_test.cpp @@ -19,7 +19,6 @@ #if defined(__BIONIC__) #define HAVE_UCHAR 1 #elif defined(__GLIBC__) -#include <features.h> #define HAVE_UCHAR __GLIBC_PREREQ(2, 16) #endif diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp index 2a656574c..8195ea8f4 100644 --- a/tests/unistd_test.cpp +++ b/tests/unistd_test.cpp @@ -431,6 +431,10 @@ TEST(unistd, getpid_caching_and_clone) { void* child_stack[1024]; int clone_result = clone(GetPidCachingCloneStartRoutine, &child_stack[1024], CLONE_NEWNS | SIGCHLD, NULL); + if (clone_result == -1 && errno == EPERM && getuid() != 0) { + GTEST_LOG_(INFO) << "This test only works if you have permission to CLONE_NEWNS; try running as root.\n"; + return; + } ASSERT_NE(clone_result, -1); ASSERT_EQ(parent_pid, getpid()); diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp index d02c4bf2f..760475fa1 100644 --- a/tests/wchar_test.cpp +++ b/tests/wchar_test.cpp @@ -489,3 +489,34 @@ TEST(wchar, mbrtowc_15439554) { EXPECT_EQ(4U, n); EXPECT_EQ(L'𤭢', wc); } + +TEST(wchar, open_wmemstream) { + wchar_t* p = nullptr; + size_t size = 0; + FILE* fp = open_wmemstream(&p, &size); + ASSERT_NE(EOF, fputws(L"hello, world!", fp)); + fclose(fp); + + ASSERT_STREQ(L"hello, world!", p); + ASSERT_EQ(wcslen(L"hello, world!"), size); + free(p); +} + +TEST(stdio, open_wmemstream_EINVAL) { +#if defined(__BIONIC__) + wchar_t* p; + size_t size; + + // Invalid buffer. + errno = 0; + ASSERT_EQ(nullptr, open_wmemstream(nullptr, &size)); + ASSERT_EQ(EINVAL, errno); + + // Invalid size. + errno = 0; + ASSERT_EQ(nullptr, open_wmemstream(&p, nullptr)); + ASSERT_EQ(EINVAL, errno); +#else + GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif +} |