resolved conflicts for merge of c8f6b82f to lmp-dev-plus-aosp
Change-Id: I03a4645eb5fbb54e41da25018729b270ba0ed48e
diff --git a/libc/Android.mk b/libc/Android.mk
index 5098171..c495e43 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -38,8 +38,6 @@
# =========================================================
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 @@
bionic/system_properties_compat.c \
stdio/snprintf.c\
stdio/sprintf.c \
+ stdio/stdio_ext.cpp \
# Fortify implementations of libc functions.
libc_common_src_files += \
@@ -121,6 +120,7 @@
bionic/getpgrp.cpp \
bionic/getpid.cpp \
bionic/gettid.cpp \
+ bionic/__gnu_basename.cpp \
bionic/inotify_init.cpp \
bionic/lchown.cpp \
bionic/lfs64_support.cpp \
@@ -132,6 +132,7 @@
bionic/link.cpp \
bionic/locale.cpp \
bionic/lstat.cpp \
+ bionic/malloc_info.cpp \
bionic/mbrtoc16.cpp \
bionic/mbrtoc32.cpp \
bionic/mbstate.cpp \
@@ -334,6 +335,9 @@
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 +347,12 @@
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 +398,7 @@
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 +427,8 @@
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 \
@@ -501,7 +514,10 @@
libc_common_cflags += -DTARGET_USES_LOGD
endif
-use_clang := false
+use_clang := $(USE_CLANG_PLATFORM_BUILD)
+ifeq ($(use_clang),)
+ use_clang := false
+endif
# Try to catch typical 32-bit assumptions that break with 64-bit pointers.
libc_common_cflags += \
@@ -637,7 +653,13 @@
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 \
@@ -731,6 +753,13 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(libc_upstream_openbsd_src_files)
+ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
+ # Clang has wrong long double size or LDBL_MANT_DIG, http://b/17163651.
+ LOCAL_CLANG := false
+else
+ LOCAL_CLANG := $(use_clang)
+endif
+
LOCAL_CFLAGS := \
$(libc_common_cflags) \
-Wno-sign-compare -Wno-uninitialized -Wno-unused-parameter \
@@ -744,7 +773,6 @@
LOCAL_CPPFLAGS := $(libc_common_cppflags)
LOCAL_C_INCLUDES := $(libc_common_c_includes)
LOCAL_MODULE := libc_openbsd
-LOCAL_CLANG := $(use_clang)
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
LOCAL_SYSTEM_SHARED_LIBRARIES :=
@@ -763,6 +791,13 @@
LOCAL_SRC_FILES_32 := $(libc_upstream_openbsd_gdtoa_src_files_32)
LOCAL_SRC_FILES_64 := $(libc_upstream_openbsd_gdtoa_src_files_64)
+ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
+ # Clang has wrong long double size or LDBL_MANT_DIG, http://b/17163651.
+ LOCAL_CLANG := false
+else
+ LOCAL_CLANG := $(use_clang)
+endif
+
LOCAL_CFLAGS := \
$(libc_common_cflags) \
-Wno-sign-compare -Wno-uninitialized \
@@ -776,7 +811,6 @@
LOCAL_CPPFLAGS := $(libc_common_cppflags)
LOCAL_C_INCLUDES := $(libc_common_c_includes)
LOCAL_MODULE := libc_gdtoa
-LOCAL_CLANG := $(use_clang)
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
LOCAL_SYSTEM_SHARED_LIBRARIES :=
@@ -794,6 +828,11 @@
LOCAL_CFLAGS := $(libc_common_cflags) \
-Wframe-larger-than=2048 \
+ifeq ($(TARGET_ARCH),x86_64)
+ # Clang assembler has problem with ssse3-strcmp-slm.S, http://b/17302991
+ LOCAL_CLANG_ASFLAGS += -no-integrated-as
+endif
+
LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
LOCAL_CPPFLAGS := $(libc_common_cppflags)
LOCAL_C_INCLUDES := $(libc_common_c_includes)
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 38ae831..bfa13b7 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -315,7 +315,7 @@
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/bionic/_setjmp.S b/libc/arch-arm/bionic/_setjmp.S
index 64a0a31..7d637fd 100644
--- a/libc/arch-arm/bionic/_setjmp.S
+++ b/libc/arch-arm/bionic/_setjmp.S
@@ -107,7 +107,7 @@
/* validation failed, die die die. */
botch:
- bl PIC_SYM(longjmperror, PLT)
- bl PIC_SYM(abort, PLT)
+ bl longjmperror
+ bl abort
b . - 8 /* Cannot get here */
END(_longjmp)
diff --git a/libc/arch-arm/bionic/abort_arm.S b/libc/arch-arm/bionic/abort_arm.S
index 6b181ef..1039502 100644
--- a/libc/arch-arm/bionic/abort_arm.S
+++ b/libc/arch-arm/bionic/abort_arm.S
@@ -40,5 +40,5 @@
.cfi_def_cfa_offset 8
.cfi_rel_offset r3, 0
.cfi_rel_offset r14, 4
- bl PIC_SYM(__libc_android_abort, PLT)
+ bl __libc_android_abort
END(abort)
diff --git a/libc/arch-arm/bionic/setjmp.S b/libc/arch-arm/bionic/setjmp.S
index ed59d07..0c9082c 100644
--- a/libc/arch-arm/bionic/setjmp.S
+++ b/libc/arch-arm/bionic/setjmp.S
@@ -56,7 +56,7 @@
.cfi_rel_offset r14, 4
mov r0, #0x00000000
- bl PIC_SYM(sigblock, PLT)
+ bl sigblock
mov r1, r0
ldmfd sp!, {r0, r14}
@@ -108,7 +108,7 @@
.cfi_adjust_cfa_offset 4
mov r0, r2
- bl PIC_SYM(sigsetmask, PLT)
+ bl sigsetmask
add sp, sp, #4 /* unalign the stack */
.cfi_adjust_cfa_offset -4
@@ -147,7 +147,7 @@
/* validation failed, die die die. */
botch:
- bl PIC_SYM(longjmperror, PLT)
- bl PIC_SYM(abort, PLT)
+ bl longjmperror
+ bl abort
b . - 8 /* Cannot get here */
END(longjmp)
diff --git a/libc/arch-arm/bionic/sigsetjmp.S b/libc/arch-arm/bionic/sigsetjmp.S
index 7016f50..6a25a12 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>
@@ -50,8 +48,8 @@
ENTRY(sigsetjmp)
teq r1, #0
- beq PIC_SYM(_setjmp, PLT)
- b PIC_SYM(setjmp, PLT)
+ beq _setjmp
+ b setjmp
END(sigsetjmp)
.L_setjmp_magic:
@@ -61,6 +59,6 @@
ldr r2, .L_setjmp_magic
ldr r3, [r0]
teq r2, r3
- beq PIC_SYM(_longjmp, PLT)
- b PIC_SYM(longjmp, PLT)
+ beq _longjmp
+ b longjmp
END(siglongjmp)
diff --git a/libc/arch-arm/include/machine/asm.h b/libc/arch-arm/include/machine/asm.h
index 7954f05..70dbe67 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
@@ -50,10 +48,4 @@
#undef __bionic_asm_function_type
#define __bionic_asm_function_type #function
-#if defined(__ELF__) && defined(PIC)
-#define PIC_SYM(x,y) x ## ( ## y ## )
-#else
-#define PIC_SYM(x,y) x
-#endif
-
#endif /* !_ARM_ASM_H_ */
diff --git a/libc/arch-arm64/bionic/_setjmp.S b/libc/arch-arm64/bionic/_setjmp.S
index 3836899..e11ef68 100644
--- a/libc/arch-arm64/bionic/_setjmp.S
+++ b/libc/arch-arm64/bionic/_setjmp.S
@@ -105,7 +105,7 @@
/* validation failed, die die die */
.L_fail:
- bl PIC_SYM(longjmperror, PLT)
- bl PIC_SYM(abort, PLT)
+ bl longjmperror
+ bl abort
b . - 8 /* Cannot get here */
END(_longjmp)
diff --git a/libc/arch-arm64/bionic/setjmp.S b/libc/arch-arm64/bionic/setjmp.S
index f9d2266..35815a6 100644
--- a/libc/arch-arm64/bionic/setjmp.S
+++ b/libc/arch-arm64/bionic/setjmp.S
@@ -45,7 +45,7 @@
stp x0, x30, [sp, #-16]!
mov x0, xzr
- bl PIC_SYM(sigblock, PLT)
+ bl sigblock
mov w1, w0
ldp x0, x30, [sp], #16
@@ -117,7 +117,7 @@
/* validation failed, die die die */
.L_fail:
- bl PIC_SYM(longjmperror, PLT)
- bl PIC_SYM(abort, PLT)
+ bl longjmperror
+ bl abort
b . - 8 /* Cannot get here */
END(longjmp)
diff --git a/libc/arch-arm64/bionic/sigsetjmp.S b/libc/arch-arm64/bionic/sigsetjmp.S
index 4fdb367..be7cecb 100644
--- a/libc/arch-arm64/bionic/sigsetjmp.S
+++ b/libc/arch-arm64/bionic/sigsetjmp.S
@@ -35,8 +35,8 @@
*/
ENTRY(sigsetjmp)
- cbz w1, PIC_SYM(_setjmp, PLT)
- b PIC_SYM(setjmp, PLT)
+ cbz w1, _setjmp
+ b setjmp
END(sigsetjmp)
.L_setjmp_magic:
@@ -46,6 +46,6 @@
ldr w2, .L_setjmp_magic
ldr w3, [x0]
cmp w2, w3
- b.eq PIC_SYM(_longjmp, PLT)
- b PIC_SYM(longjmp, PLT)
+ b.eq _longjmp
+ b longjmp
END(siglongjmp)
diff --git a/libc/arch-arm64/include/machine/asm.h b/libc/arch-arm64/include/machine/asm.h
index 4bfabaf..2bea043 100644
--- a/libc/arch-arm64/include/machine/asm.h
+++ b/libc/arch-arm64/include/machine/asm.h
@@ -38,17 +38,9 @@
#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
-#if defined(__ELF__) && defined(PIC)
-#define PIC_SYM(x,y) x ## ( ## y ## )
-#else
-#define PIC_SYM(x,y) x
-#endif
-
#endif /* _AARCH64_ASM_H_ */
diff --git a/libc/arch-mips/include/machine/asm.h b/libc/arch-mips/include/machine/asm.h
index 5eacde3..cdc7914 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/string/mips_strlen.c b/libc/arch-mips/string/mips_strlen.c
index 9fb7e6a..45fc4b4 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/syscall.S b/libc/arch-mips64/bionic/syscall.S
index c4fd009..e3710f8 100644
--- a/libc/arch-mips64/bionic/syscall.S
+++ b/libc/arch-mips64/bionic/syscall.S
@@ -52,7 +52,7 @@
#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 5eacde3..cdc7914 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 997ccec..0000000
--- 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 6a6ad51..2f10db4 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 @@
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/include/machine/asm.h b/libc/arch-x86/include/machine/asm.h
index 672493d..943f9dd 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_64/include/machine/asm.h b/libc/arch-x86_64/include/machine/asm.h
index 06da39a..28cd08f 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/bionic/daemon.c b/libc/bionic/__gnu_basename.cpp
similarity index 68%
rename from libc/bionic/daemon.c
rename to libc/bionic/__gnu_basename.cpp
index 8181d16..1eb3f65 100644
--- a/libc/bionic/daemon.c
+++ b/libc/bionic/__gnu_basename.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,44 +25,11 @@
* 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;
+#define _GNU_SOURCE 1
+#include <string.h>
- 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;
+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/clone.cpp b/libc/bionic/clone.cpp
index 0a0fdd5..9b5c9e7 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/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
index d83799a..698ab6b 100644
--- a/libc/bionic/debug_mapinfo.cpp
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -71,7 +71,7 @@
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/dlmalloc.c b/libc/bionic/dlmalloc.c
index e89c5d1..5853e7c 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 @@
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/err.c b/libc/bionic/err.c
deleted file mode 100644
index 84a3d85..0000000
--- a/libc/bionic/err.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*-
- * 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 <sys/cdefs.h>
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.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);
-}
-
-
-__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)
-{
- 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));
-}
-
-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");
-}
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 950073a..2a6a03b 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -49,7 +49,7 @@
extern "C" int __set_tls(void* ptr);
extern "C" int __set_tid_address(int* tid_address);
-void __libc_init_vdso();
+__LIBC_HIDDEN__ void __libc_init_vdso();
// Not public, but well-known in the BSDs.
const char* __progname;
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index 5655526..49a3762 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -75,10 +75,12 @@
len = strlen(data);
}
+ total += len;
+
while (len > 0) {
int avail = end_ - pos_;
if (avail == 0) {
- break;
+ return;
}
if (avail > len) {
avail = len;
@@ -87,11 +89,10 @@
pos_ += avail;
pos_[0] = '\0';
len -= avail;
- total += avail;
}
}
- int total;
+ size_t total;
private:
char* buffer_;
@@ -109,18 +110,19 @@
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_;
diff --git a/libc/bionic/malloc_info.cpp b/libc/bionic/malloc_info.cpp
new file mode 100644
index 0000000..99caedb
--- /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 0000000..5fffae9
--- /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 fcfd1bd..cd84c2e 100644
--- a/libc/bionic/new.cpp
+++ b/libc/bionic/new.cpp
@@ -38,11 +38,11 @@
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 @@
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/pututline.c b/libc/bionic/pututline.c
index c8427f7..8cbf470 100644
--- a/libc/bionic/pututline.c
+++ b/libc/bionic/pututline.c
@@ -36,7 +36,7 @@
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 @@
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/sigaction.cpp b/libc/bionic/sigaction.cpp
index 225a823..e1a031f 100644
--- a/libc/bionic/sigaction.cpp
+++ b/libc/bionic/sigaction.cpp
@@ -64,10 +64,6 @@
bionic_old_action->sa_mask = kernel_old_action.sa_mask;
#ifdef SA_RESTORER
bionic_old_action->sa_restorer = kernel_old_action.sa_restorer;
-
- if (bionic_old_action->sa_restorer == &__rt_sigreturn) {
- bionic_old_action->sa_flags &= ~SA_RESTORER;
- }
#endif
}
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index 1e57cc0..d419fb1 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 @@
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 8309f08..d8aac4f 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -95,7 +95,7 @@
}
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 __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 a564c39..ad69cf5 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -26,6 +26,7 @@
* SUCH DAMAGE.
*/
#include <new>
+#include <stdatomic.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -45,7 +46,6 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/in.h>
-#include <unistd.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
@@ -80,6 +80,16 @@
uint8_t namelen;
uint8_t reserved[3];
+ // TODO: The following fields should be declared as atomic_uint32_t.
+ // They should be assigned to with release semantics, instead of using
+ // explicit fences. Unfortunately, the read accesses are generally
+ // followed by more dependent read accesses, and the dependence
+ // is assumed to enforce memory ordering. Which it does on supported
+ // hardware. This technically should use memory_order_consume, if
+ // that worked as intended.
+ // We should also avoid rereading these fields redundantly, since not
+ // all processor implementations ensure that multiple loads from the
+ // same field are carried out in the right order.
volatile uint32_t prop;
volatile uint32_t left;
@@ -93,7 +103,8 @@
this->namelen = name_length;
memcpy(this->name, name, name_length);
this->name[name_length] = '\0';
- ANDROID_MEMBAR_FULL();
+ ANDROID_MEMBAR_FULL(); // TODO: Instead use a release store
+ // for subsequent pointer assignment.
}
private:
@@ -102,14 +113,15 @@
struct prop_area {
uint32_t bytes_used;
- volatile uint32_t serial;
+ atomic_uint_least32_t serial;
uint32_t magic;
uint32_t version;
uint32_t reserved[28];
char data[0];
prop_area(const uint32_t magic, const uint32_t version) :
- serial(0), magic(magic), version(version) {
+ magic(magic), version(version) {
+ atomic_init(&serial, 0);
memset(reserved, 0, sizeof(reserved));
// Allocate enough space for the root node.
bytes_used = sizeof(prop_bt);
@@ -120,7 +132,7 @@
};
struct prop_info {
- volatile uint32_t serial;
+ atomic_uint_least32_t serial;
char value[PROP_VALUE_MAX];
char name[0];
@@ -128,10 +140,11 @@
const uint8_t valuelen) {
memcpy(this->name, name, namelen);
this->name[namelen] = '\0';
- this->serial = (valuelen << 24);
+ atomic_init(&this->serial, valuelen << 24);
memcpy(this->value, value, valuelen);
this->value[valuelen] = '\0';
- ANDROID_MEMBAR_FULL();
+ ANDROID_MEMBAR_FULL(); // TODO: Instead use a release store
+ // for subsequent point assignment.
}
private:
DISALLOW_COPY_AND_ASSIGN(prop_info);
@@ -598,6 +611,14 @@
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)) {
@@ -605,11 +626,20 @@
}
while (true) {
- uint32_t serial = __system_property_serial(pi);
+ uint32_t serial = __system_property_serial(pi); // acquire semantics
size_t len = SERIAL_VALUE_LEN(serial);
memcpy(value, pi->value, len + 1);
- ANDROID_MEMBAR_FULL();
- if (serial == pi->serial) {
+ // TODO: Fix the synchronization scheme here.
+ // There is no fully supported way to implement this kind
+ // of synchronization in C++11, since the memcpy races with
+ // updates to pi, and the data being accessed is not atomic.
+ // The following fence is unintuitive, but would be the
+ // correct one if memcpy used memory_order_relaxed atomic accesses.
+ // In practice it seems unlikely that the generated code would
+ // would be any different, so this should be OK.
+ atomic_thread_fence(memory_order_acquire);
+ if (serial ==
+ load_const_atomic(&(pi->serial), memory_order_relaxed)) {
if (name != 0) {
strcpy(name, pi->name);
}
@@ -658,14 +688,24 @@
if (len >= PROP_VALUE_MAX)
return -1;
- pi->serial = pi->serial | 1;
- ANDROID_MEMBAR_FULL();
+ uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed);
+ serial |= 1;
+ atomic_store_explicit(&pi->serial, serial, memory_order_relaxed);
+ // The memcpy call here also races. Again pretend it
+ // used memory_order_relaxed atomics, and use the analogous
+ // counterintuitive fence.
+ atomic_thread_fence(memory_order_release);
memcpy(pi->value, value, len + 1);
- ANDROID_MEMBAR_FULL();
- pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
+ atomic_store_explicit(
+ &pi->serial,
+ (len << 24) | ((serial + 1) & 0xffffff),
+ memory_order_release);
__futex_wake(&pi->serial, INT32_MAX);
- pa->serial++;
+ atomic_store_explicit(
+ &pa->serial,
+ atomic_load_explicit(&pa->serial, memory_order_relaxed) + 1,
+ memory_order_release);
__futex_wake(&pa->serial, INT32_MAX);
return 0;
@@ -688,17 +728,25 @@
if (!pi)
return -1;
- pa->serial++;
+ // There is only a single mutator, but we want to make sure that
+ // updates are visible to a reader waiting for the update.
+ atomic_store_explicit(
+ &pa->serial,
+ atomic_load_explicit(&pa->serial, memory_order_relaxed) + 1,
+ memory_order_release);
__futex_wake(&pa->serial, INT32_MAX);
return 0;
}
+// Wait for non-locked serial, and retrieve it with acquire semantics.
unsigned int __system_property_serial(const prop_info *pi)
{
- uint32_t serial = pi->serial;
+ uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire);
while (SERIAL_DIRTY(serial)) {
- __futex_wait(const_cast<volatile uint32_t*>(&pi->serial), serial, NULL);
- serial = pi->serial;
+ __futex_wait(const_cast<volatile void *>(
+ reinterpret_cast<const void *>(&pi->serial)),
+ serial, NULL);
+ serial = load_const_atomic(&pi->serial, memory_order_acquire);
}
return serial;
}
@@ -706,12 +754,14 @@
unsigned int __system_property_wait_any(unsigned int serial)
{
prop_area *pa = __system_property_area__;
+ uint32_t my_serial;
do {
__futex_wait(&pa->serial, serial, NULL);
- } while (pa->serial == serial);
+ my_serial = atomic_load_explicit(&pa->serial, memory_order_acquire);
+ } while (my_serial == serial);
- return pa->serial;
+ return my_serial;
}
const prop_info *__system_property_find_nth(unsigned n)
diff --git a/libc/dns/gethnamaddr.c b/libc/dns/gethnamaddr.c
index 1d847b8..0bd838e 100644
--- a/libc/dns/gethnamaddr.c
+++ b/libc/dns/gethnamaddr.c
@@ -899,7 +899,7 @@
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 @@
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 2612d6a..5443999 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -2017,7 +2017,7 @@
{
if (!*hostf)
- *hostf = fopen(_PATH_HOSTS, "r" );
+ *hostf = fopen(_PATH_HOSTS, "re");
else
rewind(*hostf);
}
@@ -2046,7 +2046,7 @@
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 fa199d0..7f748f7 100644
--- a/libc/dns/net/services.h
+++ b/libc/dns/net/services.h
@@ -30,8 +30,8 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 @@
\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 93d3f19..0000000
--- 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 3af50b0..0000000
--- 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 198b05c..0000000
--- 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 419b748..057ba14 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -1453,7 +1453,7 @@
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 f1cbed8..713b6e0 100644
--- a/libc/dns/resolv/res_init.c
+++ b/libc/dns/resolv/res_init.c
@@ -289,7 +289,7 @@
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 @@
}
#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/include/arpa/inet.h b/libc/include/arpa/inet.h
index 067be1f..86265bf 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 0975b7a..7a9485a 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -69,14 +69,15 @@
#define PT_GNU_RELRO 0x6474e552
-#define STB_LOOS 10
-#define STB_HIOS 12
-#define STB_LOPROC 13
-#define STB_HIPROC 15
+#define STB_LOOS 10
+#define STB_HIOS 12
+#define STB_LOPROC 13
+#define STB_HIPROC 15
-#define STT_LOOS 10
-#define STT_HIOS 12
-#define STT_LOPROC 13
-#define STT_HIPROC 15
+#define STT_GNU_IFUNC 10
+#define STT_LOOS 10
+#define STT_HIOS 12
+#define STT_LOPROC 13
+#define STT_HIPROC 15
#endif /* _ELF_H */
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 4450bb6..32557d9 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -82,9 +82,9 @@
#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 343c84d..a279c7f 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 9dcec75..e89328e 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,8 +34,18 @@
__BEGIN_DECLS
-/* On Android these don't modify their input, and use thread-local storage for their results. */
+#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, but doesn't
+ * modify its input and uses thread-local storage for the result if necessary.
+ */
extern char* basename(const char*);
+#define __bionic_using_posix_basename
+#endif
+
+/* This has the wrong argument cv-qualifiers, but doesn't modify its input and uses thread-local storage for the result if necessary. */
extern char* dirname(const char*);
#if !defined(__LP64__)
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index e6ea276..cb1dd3b 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 @@
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 bf3b498..44c7fc1 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 @@
#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 e43b6cc..6155ab7 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -52,7 +52,7 @@
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 int __sched_cpucount(size_t setsize, cpu_set_t* set);
-#endif /* _GNU_SOURCE */
+#endif /* __USE_GNU */
__END_DECLS
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 43b0fbf..594d231 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -38,6 +38,14 @@
#ifndef _STDIO_H_
#define _STDIO_H_
+/*
+ * This file must contain a reference to __gnuc_va_list so that GCC's
+ * fixincludes knows that that's what's being used for va_list, and so
+ * to leave our <stdio.h> alone. (fixincludes gets in the way of pointing
+ * one toolchain at various different sets of platform headers.)
+ * If you alter this comment, be sure to keep "__gnuc_va_list" in it!
+ */
+
#include <sys/cdefs.h>
#include <sys/types.h>
@@ -329,6 +337,11 @@
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 */
@@ -347,6 +360,11 @@
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
/*
@@ -412,7 +430,7 @@
#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/bionic/daemon.c b/libc/include/stdio_ext.h
similarity index 67%
copy from libc/bionic/daemon.c
copy to libc/include/stdio_ext.h
index 8181d16..f299e54 100644
--- a/libc/bionic/daemon.c
+++ 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
@@ -25,44 +25,30 @@
* 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;
+#ifndef _STDIO_EXT_H
+#define _STDIO_EXT_H
- if ( !nochdir && chdir("/") != 0 )
- return -1;
-
- if ( !noclose )
- {
- int fd = open("/dev/null", O_RDWR);
+#include <sys/cdefs.h>
+#include <stdio.h>
- if ( fd < 0 )
- return -1;
+#define FSETLOCKING_QUERY 0
+#define FSETLOCKING_INTERNAL 1
+#define FSETLOCKING_BYCALLER 2
- 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;
+__BEGIN_DECLS
- if (pid > 0)
- _exit(0);
+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);
- if ( setsid() < 0 )
- return -1;
+__END_DECLS
- return 0;
-}
-
+#endif /* _STDIO_EXT_H */
diff --git a/libc/include/string.h b/libc/include/string.h
index 8df68e3..b0643af 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* 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 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 @@
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 @@
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 @@
__END_DECLS
-#endif /* _STRING_H_ */
+#endif /* _STRING_H */
diff --git a/libc/include/sys/cachectl.h b/libc/include/sys/cachectl.h
index 57e6ae7..a302ff8 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 9a8dfdd..5082327 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -267,20 +267,6 @@
#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
@@ -359,64 +345,42 @@
#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.
+ *
+ * The _GNU_SOURCE test needs to come before any _BSD_SOURCE or _POSIX* tests
+ * because _GNU_SOURCE implies everything else.
*/
-#define __FBSDID(s) /* nothing */
+#if defined(_GNU_SOURCE)
+# define __USE_GNU 1
+# undef _POSIX_SOURCE
+# define _POSIX_SOURCE 1
+# undef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200809L
+# undef _BSD_SOURCE
+# define _BSD_SOURCE 1
+#endif
+
+#if defined(_BSD_SOURCE)
+# define __USE_BSD 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 +534,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 4dd7dc3..a40a867 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 ae2f238..a8840ff 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -294,8 +294,7 @@
#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 c0c168b..b56ffa4 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 @@
#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 7fbafdf..34ae2bc 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 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 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 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 1898c7e..ae10d93 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -166,6 +166,7 @@
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 6601817..ebebe80 100755
--- a/libc/kernel/tools/clean_header.py
+++ b/libc/kernel/tools/clean_header.py
@@ -199,8 +199,7 @@
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 2be9532..0c098de 100644
--- a/libc/kernel/tools/cpp.py
+++ b/libc/kernel/tools/cpp.py
@@ -1711,7 +1711,7 @@
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 @@
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 @@
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 @@
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 0478e93..e5a310e 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 @@
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 7c2686f..d53ebba 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/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
new file mode 100644
index 0000000..bfdecb8
--- /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 c38efb5..0000000
--- 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 58a10e0..8bcf7fc 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 @@
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 @@
'__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 @@
'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:'
-allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff | std_stuff | weird_stuff)
+ print
+ print 'in bionic but not glibc:'
+
+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 316e05b..929bec4 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -4,21 +4,29 @@
# the header files listing all available system calls, and the
# makefiles used to build all the stubs.
+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 *
-bionic_libc_root = os.environ["ANDROID_BUILD_TOP"] + "/bionic/libc/"
+all_arches = [ "arm", "arm64", "mips", "mips64", "x86", "x86_64" ]
+
# temp directory where we store all intermediate files
-bionic_temp = "/tmp/bionic_gensyscalls/"
+bionic_temp = tempfile.mkdtemp(prefix="bionic_gensyscalls");
+# Make sure the directory is deleted when the script exits.
+atexit.register(shutil.rmtree, bionic_temp)
+
+bionic_libc_root = os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libc")
warning = "Generated by gensyscalls.py. Do not edit."
@@ -34,9 +42,10 @@
def create_file(relpath):
- dir = os.path.dirname(bionic_temp + relpath)
+ full_path = os.path.join(bionic_temp, relpath)
+ dir = os.path.dirname(full_path)
make_dir(dir)
- return open(bionic_temp + relpath, "w")
+ return open(full_path, "w")
syscall_stub_header = "/* " + warning + " */\n" + \
@@ -267,7 +276,7 @@
# This lets us support regular system calls like __NR_write and also weird
# ones like __ARM_NR_cacheflush, where the NR doesn't come at the start.
def make__NR_name(name):
- if name.startswith("__"):
+ if name.startswith("__ARM_NR_"):
return name
else:
return "__NR_%s" % (name)
@@ -382,6 +391,120 @@
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 = []
@@ -439,22 +562,22 @@
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")
glibc_fp.write("#define _BIONIC_GLIBC_SYSCALLS_H_\n")
glibc_fp.write("#if defined(__aarch64__)\n")
- self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-generic/unistd.h")
+ self.scan_linux_unistd_h(glibc_fp, os.path.join(bionic_libc_root, "kernel/uapi/asm-generic/unistd.h"))
glibc_fp.write("#elif defined(__arm__)\n")
- self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-arm/asm/unistd.h")
+ self.scan_linux_unistd_h(glibc_fp, os.path.join(bionic_libc_root, "kernel/uapi/asm-arm/asm/unistd.h"))
glibc_fp.write("#elif defined(__mips__)\n")
- self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-mips/asm/unistd.h")
+ self.scan_linux_unistd_h(glibc_fp, os.path.join(bionic_libc_root, "kernel/uapi/asm-mips/asm/unistd.h"))
glibc_fp.write("#elif defined(__i386__)\n")
- self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-x86/asm/unistd_32.h")
+ self.scan_linux_unistd_h(glibc_fp, os.path.join(bionic_libc_root, "kernel/uapi/asm-x86/asm/unistd_32.h"))
glibc_fp.write("#elif defined(__x86_64__)\n")
- self.scan_linux_unistd_h(glibc_fp, bionic_libc_root + "/kernel/uapi/asm-x86/asm/unistd_64.h")
+ self.scan_linux_unistd_h(glibc_fp, os.path.join(bionic_libc_root, "kernel/uapi/asm-x86/asm/unistd_64.h"))
glibc_fp.write("#endif\n")
glibc_fp.write("#endif /* _BIONIC_GLIBC_SYSCALLS_H_ */\n")
@@ -468,7 +591,7 @@
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()
@@ -476,48 +599,49 @@
def regenerate(self):
- D("scanning for existing architecture-specific stub files...")
-
- bionic_libc_root_len = len(bionic_libc_root)
+ logging.info("scanning for existing architecture-specific stub files...")
for arch in all_arches:
- arch_path = bionic_libc_root + "arch-" + arch
- D("scanning " + arch_path)
- files = glob.glob(arch_path + "/syscalls/*.S")
- for f in files:
- self.old_stubs.append(f[bionic_libc_root_len:])
+ arch_dir = "arch-" + arch
+ 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 = []
for stub in self.new_stubs + self.other_files:
- if not os.path.exists(bionic_libc_root + stub):
+ tmp_file = os.path.join(bionic_temp, stub)
+ 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)
- adds.append(bionic_libc_root + stub)
- shutil.copyfile(bionic_temp + stub, bionic_libc_root + stub)
+ logging.info("new file: " + stub)
+ adds.append(libc_file)
+ shutil.copyfile(tmp_file, libc_file)
- elif not filecmp.cmp(bionic_temp + stub, bionic_libc_root + stub):
- D("changed file: " + stub)
+ elif not filecmp.cmp(tmp_file, libc_file):
+ 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)
- deletes.append(bionic_libc_root + stub)
+ logging.info("deleted file: " + stub)
+ deletes.append(os.path.join(bionic_libc_root, stub))
if not DRY_RUN:
if adds:
@@ -526,18 +650,19 @@
commands.getoutput("git rm " + " ".join(deletes))
if edits:
for file in edits:
- shutil.copyfile(bionic_temp + file, bionic_libc_root + file)
- commands.getoutput("git add " + " ".join((bionic_libc_root + file) for file in edits))
+ shutil.copyfile(os.path.join(bionic_temp, file),
+ os.path.join(bionic_libc_root, file))
+ commands.getoutput("git add " + " ".join((os.path.join(bionic_libc_root, file)) for file in edits))
- commands.getoutput("git add %s%s" % (bionic_libc_root,"SYSCALLS.TXT"))
+ 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(bionic_libc_root+"SYSCALLS.TXT")
+state.process_file(os.path.join(bionic_libc_root, "SYSCALLS.TXT"))
state.regenerate()
diff --git a/libc/upstream-freebsd/android/include/freebsd-compat.h b/libc/upstream-freebsd/android/include/freebsd-compat.h
index d5f1425..b44b94a 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 5df543c..630ea9b 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 84be931..04bc728 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 34ad2c5..630094d 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 0000000..79f4264
--- /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 0000000..e7ec29d
--- /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 0000000..d213435
--- /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/upstream-openbsd/lib/libc/gen/verr.c b/libc/upstream-openbsd/lib/libc/gen/verr.c
new file mode 100644
index 0000000..dcd8edc
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/verr.c
@@ -0,0 +1,56 @@
+/* $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.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+extern char *__progname; /* Program name, from crt0. */
+
+__dead 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);
+}
+
+__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 0000000..60da062
--- /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 0000000..26b60f3
--- /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 0000000..e6b1957
--- /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 0000000..c1b47a6
--- /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 0000000..af2ab66
--- /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 0000000..f28692f
--- /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 0000000..8cda047
--- /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 0000000..4610535
--- /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 0000000..9414187
--- /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/libm/Android.mk b/libm/Android.mk
index 994caa0..f59b71f 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -255,6 +255,10 @@
# libm.a for target.
#
include $(CLEAR_VARS)
+ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
+# Clang has wrong long double sizes for x86.
+LOCAL_CLANG := false
+endif
LOCAL_MODULE:= libm
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_ARM_MODE := arm
@@ -287,6 +291,10 @@
# libm.so for target.
#
include $(CLEAR_VARS)
+ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
+# Clang has wrong long double sizes for x86.
+LOCAL_CLANG := false
+endif
LOCAL_MODULE:= libm
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_SYSTEM_SHARED_LIBRARIES := libc
diff --git a/libm/include/math.h b/libm/include/math.h
index 3eca140..1fcc578 100644
--- a/libm/include/math.h
+++ b/libm/include/math.h
@@ -462,11 +462,11 @@
#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 ad75549..a5608cf 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++/include/new b/libstdc++/include/new
index 0253e8b..c5a43de 100644
--- a/libstdc++/include/new
+++ b/libstdc++/include/new
@@ -13,19 +13,19 @@
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/linker/Android.mk b/linker/Android.mk
index 5853c90..d6e0095 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -8,6 +8,7 @@
linker.cpp \
linker_allocator.cpp \
linker_environ.cpp \
+ linker_libc_support.c \
linker_phdr.cpp \
rt.cpp \
@@ -44,13 +45,11 @@
# TODO: split out the asflags.
LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/linker_executable.mk
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_STATIC_LIBRARIES := libc_nomalloc
-LOCAL_FORCE_STATIC_EXECUTABLE := true # not necessary when not including BUILD_EXECUTABLE
-
-LOCAL_2ND_ARCH_VAR_PREFIX := $(linker_2nd_arch_var_prefix)
+LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE := linker
LOCAL_MODULE_STEM_32 := linker
@@ -61,17 +60,12 @@
# 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)
-OVERRIDE_BUILT_MODULE_PATH :=
-LOCAL_BUILT_MODULE :=
-LOCAL_INSTALLED_MODULE :=
-LOCAL_MODULE_STEM :=
-LOCAL_BUILT_MODULE_STEM :=
-LOCAL_INSTALLED_MODULE_STEM :=
-LOCAL_INTERMEDIATE_TARGETS :=
-include $(LOCAL_PATH)/linker_executable.mk
-endif
+# Insert an extra objcopy step to add prefix to symbols.
+# Note we are using "=" instead of ":=" to defer the evaluation,
+# because LOCAL_2ND_ARCH_VAR_PREFIX or linked_module isn't set properly yet at this point.
+LOCAL_POST_LINK_CMD = $(hide) $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJCOPY) \
+ --prefix-symbols=__dl_ $(linked_module)
+
+include $(BUILD_EXECUTABLE)
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index c316151..6565985 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -162,12 +162,12 @@
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.
__libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
@@ -198,7 +198,7 @@
}
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 @@
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 @@
// 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 @@
// 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 5d6db8e..38484d9 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -42,7 +42,7 @@
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 @@
}
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 @@
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,33 +80,33 @@
}
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;
+ soinfo* found = nullptr;
+ ElfW(Sym)* sym = nullptr;
if (handle == RTLD_DEFAULT) {
- sym = dlsym_linear_lookup(symbol, &found, NULL);
+ sym = dlsym_linear_lookup(symbol, &found, nullptr);
} else if (handle == RTLD_NEXT) {
void* caller_addr = __builtin_return_address(0);
soinfo* si = find_containing_library(caller_addr);
- sym = NULL;
+ sym = nullptr;
if (si && si->next) {
sym = dlsym_linear_lookup(symbol, &found, si->next);
}
@@ -114,7 +114,7 @@
sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
}
- if (sym != NULL) {
+ if (sym != nullptr) {
unsigned bind = ELF_ST_BIND(sym->st_info);
if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
@@ -122,10 +122,10 @@
}
__bionic_format_dlerror("symbol found but not global", symbol);
- return NULL;
+ return nullptr;
} else {
__bionic_format_dlerror("undefined symbol", symbol);
- return NULL;
+ return nullptr;
}
}
@@ -134,7 +134,7 @@
// 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;
}
@@ -146,7 +146,7 @@
// 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);
}
@@ -164,7 +164,7 @@
// 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, \
@@ -176,7 +176,7 @@
(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, \
}
@@ -199,7 +199,7 @@
// 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),
@@ -232,17 +232,12 @@
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 8096e62..5fbdc8f 100644
--- a/linker/linked_list.h
+++ b/linker/linked_list.h
@@ -32,6 +32,9 @@
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 @@
}
template<typename F>
- void for_each(F&& action) {
- for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
- if (e->element != nullptr) {
- action(e->element);
- }
- }
+ void for_each(F action) {
+ visit([&] (T* si) {
+ action(si);
+ return true;
+ });
}
template<typename F>
- void remove_if(F&& predicate) {
+ bool visit(F action) {
for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
- if (e->element != nullptr && predicate(e->element)) {
- e->element = nullptr;
+ if (!action(e->element)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ template<typename F>
+ 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) {
- if (e->element != nullptr && e->element == el) {
+ ++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 == el) {
return true;
}
}
diff --git a/linker/linker.cpp b/linker/linker.cpp
index cf65705..2186b3d 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 @@
#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 @@
"/vendor/lib",
"/system/lib",
#endif
- NULL
+ nullptr
};
#define LDPATH_BUFSIZE (LDPATH_MAX*64)
@@ -115,7 +115,7 @@
__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,
@@ -188,7 +188,7 @@
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) {
@@ -287,20 +287,10 @@
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;
@@ -310,7 +300,7 @@
}
static void soinfo_free(soinfo* si) {
- if (si == NULL) {
+ if (si == nullptr) {
return;
}
@@ -318,16 +308,16 @@
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;
@@ -336,7 +326,7 @@
// 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;
@@ -350,7 +340,7 @@
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;
}
@@ -367,9 +357,9 @@
// 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;
}
}
@@ -405,7 +395,7 @@
}
}
*pcount = 0;
- return NULL;
+ return nullptr;
}
#endif
@@ -414,7 +404,7 @@
* 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;
@@ -463,7 +453,46 @@
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);
+ }
+}
+
+void soinfo::resolve_ifunc_symbols() {
+ if (!get_has_ifuncs()) {
+ return;
+ }
+
+ phdr_table_unprotect_segments(phdr, phnum, load_bias);
+
+ TRACE_TYPE(IFUNC, "CHECKING FOR IFUNCS AND PERFORMING SYMBOL UPDATES");
+
+ 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.
+ // In order to return the proper value, we run the choosing function
+ // 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 + base);
+ s->st_value = (ifunc_ptr() - base);
+ TRACE_TYPE(IFUNC, "NEW VALUE IS %p", (void*)s->st_value);
+ }
+ }
+ phdr_table_protect_segments(phdr, phnum, load_bias);
}
static unsigned elfhash(const char* _name) {
@@ -479,11 +508,11 @@
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.
@@ -491,7 +520,7 @@
if (si == somain) {
s = soinfo_elf_lookup(si, elf_hash, name);
- if (s != NULL) {
+ if (s != nullptr) {
*lsi = si;
goto done;
}
@@ -517,7 +546,7 @@
DEBUG("%s: looking up %s in executable %s",
si->name, name, somain->name);
s = soinfo_elf_lookup(somain, elf_hash, name);
- if (s != NULL) {
+ if (s != nullptr) {
*lsi = somain;
goto done;
}
@@ -543,7 +572,7 @@
* Here we return the first definition found for simplicity. */
s = soinfo_elf_lookup(si, elf_hash, name);
- if (s != NULL) {
+ if (s != nullptr) {
*lsi = si;
goto done;
}
@@ -557,7 +586,7 @@
DEBUG("%s: looking up %s in executable %s after local scope",
si->name, name, somain->name);
s = soinfo_elf_lookup(somain, elf_hash, name);
- if (s != NULL) {
+ if (s != nullptr) {
*lsi = somain;
goto done;
}
@@ -574,18 +603,18 @@
}
}
- 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);
- 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),
@@ -594,11 +623,45 @@
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:
@@ -614,8 +677,9 @@
// 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) {
- LinkedList<soinfo, SoinfoListAllocatorRW> visit_list;
- LinkedList<soinfo, SoinfoListAllocatorRW> visited;
+ SoinfoLinkedList visit_list;
+ SoinfoLinkedList visited;
+
visit_list.push_back(si);
soinfo* current_soinfo;
while ((current_soinfo = visit_list.pop_front()) != nullptr) {
@@ -627,8 +691,6 @@
if (result != nullptr) {
*found = current_soinfo;
- visit_list.clear();
- visited.clear();
return result;
}
visited.push_back(current_soinfo);
@@ -638,8 +700,6 @@
});
}
- visit_list.clear();
- visited.clear();
return nullptr;
}
@@ -651,20 +711,20 @@
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) {
+ 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 != NULL) {
+ 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));
}
@@ -674,12 +734,12 @@
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) {
@@ -696,12 +756,12 @@
}
}
- 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);
@@ -719,7 +779,7 @@
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;
@@ -742,14 +802,14 @@
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);
@@ -760,12 +820,12 @@
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 &&
@@ -776,17 +836,17 @@
}
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();
@@ -799,9 +859,9 @@
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;
}
return si;
@@ -809,16 +869,16 @@
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;
}
@@ -826,14 +886,14 @@
// 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;
@@ -841,7 +901,7 @@
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;
@@ -852,18 +912,25 @@
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
@@ -910,15 +977,15 @@
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);
@@ -931,30 +998,77 @@
protect_data(PROT_READ);
}
+// ifuncs are only defined for x86
+#if defined(__i386__)
+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;
+ unsigned type = ELFW(R_TYPE)(rel->r_info);
+ 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 = nullptr;
+ sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
+ 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));
+ ElfW(Addr) (*ifunc_ptr)();
+ ifunc_ptr = reinterpret_cast<ElfW(Addr)(*)()>(s->st_value + si->base);
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_ptr();
+ }
+ }
+}
+#endif
+
+#if defined(__x86_64__)
+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;
+ 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) sym_addr = 0;
+ 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);
+
+ 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));
+ ElfW(Addr) (*ifunc_ptr)();
+ ifunc_ptr = reinterpret_cast<ElfW(Addr)(*)()>(s->st_value + si->base);
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_ptr();
+ }
+ }
+}
+#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;
}
@@ -1006,7 +1120,7 @@
}
count_relocation(kRelocSymbol);
} else {
- s = NULL;
+ s = nullptr;
}
switch (type) {
@@ -1112,8 +1226,8 @@
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:
@@ -1126,7 +1240,7 @@
* 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",
@@ -1142,7 +1256,11 @@
MARK(rela->r_offset);
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);
- *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
+ if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
+ set_has_ifuncs(true);
+ } else {
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
+ }
break;
case R_X86_64_GLOB_DAT:
count_relocation(kRelocAbsolute);
@@ -1159,8 +1277,8 @@
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);
@@ -1195,8 +1313,7 @@
}
#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;
@@ -1204,22 +1321,22 @@
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;
}
@@ -1274,7 +1391,7 @@
}
count_relocation(kRelocSymbol);
} else {
- s = NULL;
+ s = nullptr;
}
switch (type) {
@@ -1314,14 +1431,18 @@
* 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:
count_relocation(kRelocAbsolute);
MARK(rel->r_offset);
TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
- *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
+ if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
+ set_has_ifuncs(true);
+ } else {
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
+ }
break;
case R_386_GLOB_DAT:
count_relocation(kRelocAbsolute);
@@ -1362,7 +1483,7 @@
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
@@ -1379,8 +1500,8 @@
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:
@@ -1393,9 +1514,9 @@
#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;
@@ -1426,8 +1547,8 @@
// 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) {
@@ -1447,7 +1568,7 @@
#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;
}
@@ -1466,7 +1587,7 @@
}
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;
}
@@ -1502,7 +1623,7 @@
// 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);
@@ -1517,6 +1638,8 @@
// 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() {
@@ -1534,16 +1657,14 @@
}
void soinfo::add_child(soinfo* child) {
- if ((this->flags & FLAG_NEW_SOINFO) == 0) {
- return;
+ if (has_min_version(0)) {
+ child->parents.push_back(this);
+ this->children.push_back(child);
}
-
- 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;
}
@@ -1555,7 +1676,7 @@
});
parents.for_each([&] (soinfo* parent) {
- parent->children.for_each([&] (const soinfo* child) {
+ parent->children.remove_if([&] (const soinfo* child) {
return child == this;
});
});
@@ -1566,35 +1687,45 @@
}
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 (has_min_version(1)) {
+ 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 (has_min_version(1)) {
+ return has_ifuncs;
+ }
+
+ return false;
}
// This is a return on get_children() in case
@@ -1602,11 +1733,11 @@
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
@@ -1670,84 +1801,80 @@
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:
@@ -1765,67 +1892,67 @@
#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;
@@ -1833,14 +1960,14 @@
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__)
@@ -1851,7 +1978,7 @@
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;
@@ -1862,15 +1989,15 @@
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
@@ -1882,150 +2009,157 @@
}
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;
}
}
#endif
+ // if there are ifuncs, we need to do an additional relocation pass.
+ // 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(get_has_ifuncs()) {
+#if defined(__i386__)
+ soinfo_ifunc_relocate(this, plt_rel, plt_rel_count);
+#elif defined(__x86_64__)
+ 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;
}
@@ -2037,11 +2171,11 @@
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;
@@ -2049,14 +2183,19 @@
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"
@@ -2066,12 +2205,6 @@
* 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;
/*
@@ -2083,7 +2216,7 @@
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);
}
@@ -2093,16 +2226,6 @@
* 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);
@@ -2121,14 +2244,14 @@
// 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");
@@ -2136,8 +2259,8 @@
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);
}
@@ -2147,8 +2270,8 @@
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;
@@ -2174,7 +2297,7 @@
break;
}
}
- si->dynamic = NULL;
+ si->dynamic = nullptr;
si->ref_count = 1;
ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
@@ -2189,7 +2312,7 @@
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);
}
@@ -2198,11 +2321,11 @@
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.
@@ -2211,7 +2334,7 @@
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)));
@@ -2290,10 +2413,6 @@
* 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);
@@ -2301,8 +2420,7 @@
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
@@ -2314,16 +2432,15 @@
__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
@@ -2335,9 +2452,17 @@
_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 374652e..6547d68 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,29 +198,45 @@
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();
void set_st_dev(dev_t st_dev);
void set_st_ino(ino_t st_ino);
+ void set_has_ifuncs(bool ifunc);
ino_t get_st_ino();
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;
+ uint32_t version;
+ // version >= 0
dev_t st_dev;
ino_t st_ino;
@@ -225,6 +244,8 @@
soinfo_list_t children;
soinfo_list_t parents;
+ // version >= 1
+ bool has_ifuncs;
};
extern soinfo* get_libdl_info();
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 3faa38e..0c7a784 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -42,6 +42,7 @@
#define TRACE_DEBUG 1
#define DO_TRACE_LOOKUP 1
#define DO_TRACE_RELO 1
+#define DO_TRACE_IFUNC 1
#define TIMING 0
#define STATS 0
#define COUNT_PAGES 0
diff --git a/linker/linker_environ.cpp b/linker/linker_environ.cpp
index 846624b..daee56f 100644
--- a/linker/linker_environ.cpp
+++ b/linker/linker_environ.cpp
@@ -58,7 +58,7 @@
// 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 @@
return envstr + i + 1;
}
- return NULL;
+ return nullptr;
}
static bool __is_valid_environment_variable(const char* name) {
@@ -78,7 +78,7 @@
// 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 @@
"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 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 @@
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 @@
}
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 d3f54fd..0f6ac08 100644
--- a/linker/linker_environ.h
+++ b/linker/linker_environ.h
@@ -35,7 +35,7 @@
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/linker/linker_executable.mk b/linker/linker_executable.mk
deleted file mode 100644
index 4902a0c..0000000
--- a/linker/linker_executable.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-
-#
-# Instead of including $(BUILD_EXECUTABLE), we execute the steps to create an executable by
-# hand, as we want to insert an extra objcopy step that is not supported by the build
-# system, and is probably specific the linker only, so there's no need to modify the build
-# system for the purpose.
-#
-
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_SUFFIX := $(TARGET_EXECUTABLE_SUFFIX)
-
-include $(BUILD_SYSTEM)/dynamic_binary.mk
-
-# See build/core/executable_internal.mk
-$(linked_module): PRIVATE_TARGET_GLOBAL_LD_DIRS := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_GLOBAL_LD_DIRS)
-$(linked_module): PRIVATE_TARGET_GLOBAL_LDFLAGS := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_GLOBAL_LDFLAGS)
-$(linked_module): PRIVATE_TARGET_FDO_LIB := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_FDO_LIB)
-$(linked_module): PRIVATE_TARGET_LIBGCC := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_LIBGCC)
-$(linked_module): PRIVATE_TARGET_CRTBEGIN_DYNAMIC_O := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CRTBEGIN_DYNAMIC_O)
-$(linked_module): PRIVATE_TARGET_CRTBEGIN_STATIC_O := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CRTBEGIN_STATIC_O)
-$(linked_module): PRIVATE_TARGET_CRTEND_O := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CRTEND_O)
-$(linked_module): PRIVATE_TARGET_OBJCOPY := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJCOPY)
-$(linked_module): $(TARGET_CRTBEGIN_STATIC_O) $(all_objects) $(all_libraries) $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CRTEND_O)
- $(transform-o-to-static-executable)
- @echo "target PrefixSymbols: $(PRIVATE_MODULE) ($@)"
- $(hide) $(PRIVATE_TARGET_OBJCOPY) --prefix-symbols=__dl_ $@
diff --git a/linker/linker_libc_support.c b/linker/linker_libc_support.c
new file mode 100644
index 0000000..17db6d4
--- /dev/null
+++ b/linker/linker_libc_support.c
@@ -0,0 +1,17 @@
+/*
+ * 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 "../libc/arch-common/bionic/__dso_handle.h"
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 0b99d20..1bbd577 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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
* 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 @@
*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 @@
}
return;
}
- *dynamic = NULL;
+ *dynamic = nullptr;
if (dynamic_count) {
*dynamic_count = 0;
}
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 611f1a7..50708a0 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -81,7 +81,7 @@
};
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 b9816fa..a555edb 100644
--- a/linker/tests/linked_list_test.cpp
+++ b/linker/tests/linked_list_test.cpp
@@ -80,7 +80,7 @@
});
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 @@
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 8184bf7..3bd4ec0 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -92,8 +92,10 @@
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_c_includes := \
bionic/libc \
+ external/tinyxml2 \
libBionicStandardTests_ldlibs_host := \
-lrt \
@@ -243,6 +246,10 @@
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 \
@@ -256,6 +263,7 @@
-Wl,-u,DlSymTestFunction \
bionic-unit-tests_c_includes := \
+ bionic/libc \
$(call include-path-for, libpagemap) \
bionic-unit-tests_shared_libraries_target := \
@@ -281,6 +289,8 @@
libm \
libc \
libstdc++ \
+ libtinyxml2 \
+ liblog \
bionic-unit-tests-static_force_static_executable := true
@@ -356,6 +366,22 @@
$(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 e01220e..e92889d 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 @@
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 da63046..7bd59c8 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -117,7 +117,7 @@
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 @@
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 @@
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, 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 457fcd5..1613ee8 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -22,6 +22,8 @@
#include <stdio.h>
#include <stdint.h>
+#include "private/ScopeGuard.h"
+
#include <string>
#define ASSERT_SUBSTR(needle, haystack) \
@@ -87,6 +89,75 @@
ASSERT_EQ(0, dlclose(handle2));
}
+// ifuncs are only supported on intel for now
+#if defined(__i386__) || defined(__x86_64__)
+TEST(dlfcn, ifunc) {
+ 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);
+ 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);
+ dlclose(handle);
+
+ // then check the unset case
+ unsetenv("IFUNC_CHOICE");
+ handle = dlopen("libtest_ifunc.so", RTLD_NOW);
+ ASSERT_TRUE(handle != NULL);
+ 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);
+ 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
+
+TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
+ // This is the structure of the test library and
+ // its dt_needed libraries
+ // libtest_relo_check_dt_needed_order.so
+ // |
+ // +-> libtest_relo_check_dt_needed_order_1.so
+ // |
+ // +-> libtest_relo_check_dt_needed_order_2.so
+ //
+ // The root library references relo_test_get_answer_lib - which is defined
+ // in both dt_needed libraries, the correct relocation should
+ // use the function defined in libtest_relo_check_dt_needed_order_1.so
+ void* handle = nullptr;
+ auto guard = create_scope_guard([&]() {
+ dlclose(handle);
+ });
+
+ handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+
+ typedef int (*fn_t) (void);
+ fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer"));
+ ASSERT_TRUE(fn != nullptr) << dlerror();
+ ASSERT_EQ(1, fn());
+}
+
TEST(dlfcn, dlopen_failure) {
void* self = dlopen("/does/not/exist", RTLD_NOW);
ASSERT_TRUE(self == NULL);
@@ -295,4 +366,6 @@
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 51c9db8..b331150 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 950161e..d4ceded 100644
--- a/tests/libc_logging_test.cpp
+++ b/tests/libc_logging_test.cpp
@@ -176,3 +176,15 @@
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 3958f81..e9a5d5c 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 @@
// 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 75df539..dc38ae5 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.
# -----------------------------------------------------------------------------
@@ -102,6 +103,29 @@
include $(TEST_PATH)/Android.build.mk
# -----------------------------------------------------------------------------
+# libtest_relo_check_dt_needed_order.so
+# |
+# +-> libtest_relo_check_dt_needed_order_1.so
+# |
+# +-> libtest_relo_check_dt_needed_order_2.so
+# -----------------------------------------------------------------------------
+libtest_relo_check_dt_needed_order_shared_libraries := \
+ libtest_relo_check_dt_needed_order_1 libtest_relo_check_dt_needed_order_2
+
+libtest_relo_check_dt_needed_order_src_files := dlopen_testlib_relo_check_dt_needed_order.cpp
+libtest_relo_check_dt_needed_order_1_src_files := dlopen_testlib_relo_check_dt_needed_order_1.cpp
+libtest_relo_check_dt_needed_order_2_src_files := dlopen_testlib_relo_check_dt_needed_order_2.cpp
+build_type := target
+build_target := SHARED_LIBRARY
+
+module := libtest_relo_check_dt_needed_order
+include $(TEST_PATH)/Android.build.mk
+module := libtest_relo_check_dt_needed_order_1
+include $(TEST_PATH)/Android.build.mk
+module := libtest_relo_check_dt_needed_order_2
+include $(TEST_PATH)/Android.build.mk
+
+# -----------------------------------------------------------------------------
# Library with dependency used by dlfcn tests
# -----------------------------------------------------------------------------
libtest_with_dependency_src_files := \
@@ -115,6 +139,20 @@
include $(TEST_PATH)/Android.build.mk
# -----------------------------------------------------------------------------
+# Library used by ifunc tests
+# -----------------------------------------------------------------------------
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64))
+ libtest_ifunc_src_files := \
+ dlopen_testlib_ifunc.c
+
+ LOCAL_SDK_VERSION := current
+ module := libtest_ifunc
+ build_type := target
+ build_target := SHARED_LIBRARY
+ include $(TEST_PATH)/Android.build.mk
+endif
+
+# -----------------------------------------------------------------------------
# Library used by atexit tests
# -----------------------------------------------------------------------------
diff --git a/tests/libs/atexit_testlib.cpp b/tests/libs/atexit_testlib.cpp
index d35f57b..314e8de 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_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 @@
*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
new file mode 100644
index 0000000..4874841
--- /dev/null
+++ b/tests/libs/dlopen_testlib_ifunc.c
@@ -0,0 +1,56 @@
+/*
+ * 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.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";
+}
+
+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;
+}
+
+const char* foo_library() {
+ return foo();
+}
diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp
new file mode 100644
index 0000000..d8fb543
--- /dev/null
+++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+extern "C" int relo_test_get_answer_lib();
+
+extern "C" int relo_test_get_answer() {
+ return relo_test_get_answer_lib();
+}
diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp
new file mode 100644
index 0000000..4c877d0
--- /dev/null
+++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+extern "C" int relo_test_get_answer_lib() {
+ return 1;
+}
diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp
new file mode 100644
index 0000000..10288a0
--- /dev/null
+++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+extern "C" int relo_test_get_answer_lib() {
+ return 2;
+}
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 6b7a28b..b76625a 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 @@
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 c0a2d82..4917e87 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 @@
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 ea95ff3..8520c1d 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 @@
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 beb2584..c9c6ad5 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 @@
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 257aa26..30bc946 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 @@
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 da2a848..4f136a7 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 @@
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 e5d0921..ca02095 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 @@
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 c185424..a4caa36 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 @@
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 f77b23a..7272644 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 @@
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 ffa4340..509642c 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 @@
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 0fab2c2..4093fb9 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 @@
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 c1a32c9..d30f72e 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 @@
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 bb1e2c9..0c2e6f1 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 @@
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 6862019..e555ef3 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 @@
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 9319046..db04116 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 @@
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/math_test.cpp b/tests/math_test.cpp
index b4f5b14..ad4654e 100644
--- a/tests/math_test.cpp
+++ b/tests/math_test.cpp
@@ -53,6 +53,8 @@
#include <limits.h>
#include <stdint.h>
+#include <private/ScopeGuard.h>
+
float float_subnormal() {
union {
float f;
@@ -760,6 +762,10 @@
}
TEST(math, lrint) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
+
fesetround(FE_UPWARD); // lrint/lrintf/lrintl obey the rounding mode.
ASSERT_EQ(1235, lrint(1234.01));
ASSERT_EQ(1235, lrintf(1234.01f));
@@ -780,6 +786,10 @@
}
TEST(math, rint) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
+
fesetround(FE_UPWARD); // rint/rintf/rintl obey the rounding mode.
feclearexcept(FE_ALL_EXCEPT); // rint/rintf/rintl do set the FE_INEXACT flag.
ASSERT_EQ(1234.0, rint(1234.0));
@@ -806,6 +816,9 @@
}
TEST(math, nearbyint) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
fesetround(FE_UPWARD); // nearbyint/nearbyintf/nearbyintl obey the rounding mode.
feclearexcept(FE_ALL_EXCEPT); // nearbyint/nearbyintf/nearbyintl don't set the FE_INEXACT flag.
ASSERT_EQ(1234.0, nearbyint(1234.0));
@@ -832,6 +845,9 @@
}
TEST(math, lround) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
fesetround(FE_UPWARD); // lround ignores the rounding mode.
ASSERT_EQ(1234, lround(1234.01));
ASSERT_EQ(1234, lroundf(1234.01f));
@@ -839,6 +855,9 @@
}
TEST(math, llround) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
fesetround(FE_UPWARD); // llround ignores the rounding mode.
ASSERT_EQ(1234L, llround(1234.01));
ASSERT_EQ(1234L, llroundf(1234.01f));
@@ -933,6 +952,9 @@
}
TEST(math, round) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
fesetround(FE_TOWARDZERO); // round ignores the rounding mode and always rounds away from zero.
ASSERT_DOUBLE_EQ(1.0, round(0.5));
ASSERT_DOUBLE_EQ(-1.0, round(-0.5));
@@ -943,6 +965,9 @@
}
TEST(math, roundf) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
fesetround(FE_TOWARDZERO); // roundf ignores the rounding mode and always rounds away from zero.
ASSERT_FLOAT_EQ(1.0f, roundf(0.5f));
ASSERT_FLOAT_EQ(-1.0f, roundf(-0.5f));
@@ -953,6 +978,9 @@
}
TEST(math, roundl) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
fesetround(FE_TOWARDZERO); // roundl ignores the rounding mode and always rounds away from zero.
ASSERT_DOUBLE_EQ(1.0L, roundl(0.5L));
ASSERT_DOUBLE_EQ(-1.0L, roundl(-0.5L));
@@ -963,6 +991,9 @@
}
TEST(math, trunc) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
fesetround(FE_UPWARD); // trunc ignores the rounding mode and always rounds toward zero.
ASSERT_DOUBLE_EQ(1.0, trunc(1.5));
ASSERT_DOUBLE_EQ(-1.0, trunc(-1.5));
@@ -973,6 +1004,9 @@
}
TEST(math, truncf) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
fesetround(FE_UPWARD); // truncf ignores the rounding mode and always rounds toward zero.
ASSERT_FLOAT_EQ(1.0f, truncf(1.5f));
ASSERT_FLOAT_EQ(-1.0f, truncf(-1.5f));
@@ -983,6 +1017,9 @@
}
TEST(math, truncl) {
+ auto guard = create_scope_guard([]() {
+ fesetenv(FE_DFL_ENV);
+ });
fesetround(FE_UPWARD); // truncl ignores the rounding mode and always rounds toward zero.
ASSERT_DOUBLE_EQ(1.0L, truncl(1.5L));
ASSERT_DOUBLE_EQ(-1.0L, truncl(-1.5L));
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 4a7c6bd..9a9e515 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -106,6 +106,7 @@
ASSERT_EQ(99, WEXITSTATUS(status));
ASSERT_EQ(expected, pthread_getspecific(key));
+ ASSERT_EQ(0, pthread_key_delete(key));
}
static void* DirtyKeyFn(void* key) {
@@ -133,6 +134,7 @@
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) {
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 89b8088..8fd8b72 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
+#include <signal.h>
#include <errno.h>
-#include <signal.h>
+#include <gtest/gtest.h>
#include "ScopedSignalHandler.h"
@@ -198,13 +198,19 @@
static void EmptySignalAction(int, siginfo_t*, void*) {}
TEST(signal, sigaction) {
+ // Both bionic and glibc set SA_RESTORER when talking to the kernel on arm,
+ // arm64, x86, and x86-64. The version of glibc we're using also doesn't
+ // define SA_RESTORER, but luckily it's the same value everywhere, and mips
+ // doesn't use the bit for anything.
+ static const unsigned sa_restorer = 0x4000000;
+
// See what's currently set for SIGALRM.
struct sigaction original_sa;
memset(&original_sa, 0, sizeof(original_sa));
ASSERT_EQ(0, sigaction(SIGALRM, NULL, &original_sa));
ASSERT_TRUE(original_sa.sa_handler == NULL);
ASSERT_TRUE(original_sa.sa_sigaction == NULL);
- ASSERT_TRUE(original_sa.sa_flags == 0);
+ ASSERT_EQ(0U, original_sa.sa_flags & ~sa_restorer);
// Set a traditional sa_handler signal handler.
struct sigaction sa;
@@ -219,7 +225,7 @@
ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa));
ASSERT_TRUE(sa.sa_handler == EmptySignalHandler);
ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler);
- ASSERT_TRUE(sa.sa_flags == SA_ONSTACK);
+ ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK), sa.sa_flags & ~sa_restorer);
// Set a new-style sa_sigaction signal handler.
memset(&sa, 0, sizeof(sa));
@@ -233,7 +239,7 @@
ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa));
ASSERT_TRUE(sa.sa_sigaction == EmptySignalAction);
ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler);
- ASSERT_TRUE(sa.sa_flags == (SA_ONSTACK | SA_SIGINFO));
+ ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK | SA_SIGINFO), sa.sa_flags & ~sa_restorer);
// Put everything back how it was.
ASSERT_EQ(0, sigaction(SIGALRM, &original_sa, NULL));
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
new file mode 100644
index 0000000..3dbc485
--- /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 8c8c235..c01ab68 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -677,3 +677,82 @@
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 0000000..09cebfe
--- /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 73c94c6..6ecbb64 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 @@
#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) {
@@ -129,8 +137,7 @@
ASSERT_STREQ("Unknown signal 1001", strsignal1001);
}
-// TODO: where did these numbers come from?
-#define POS_ITER 10
+// TODO: where did this number come from?
#define ITER 500
// For every length we want to test, vary and change alignment
@@ -139,8 +146,9 @@
// These tests contributed by Intel Corporation.
// TODO: make these tests more intention-revealing and less random.
template<class Character>
-struct StringTestState {
- StringTestState(size_t MAX_LEN) : MAX_LEN(MAX_LEN) {
+class StringTestState {
+ public:
+ StringTestState(size_t MAX_LEN) : MAX_LEN(MAX_LEN), align1_index_(0), align2_index_(0) {
int max_alignment = 64;
// TODO: fix the tests to not sometimes use twice their specified "MAX_LEN".
@@ -159,24 +167,42 @@
free(glob_ptr2);
}
- void NewIteration() {
- int alignments[] = { 24, 32, 16, 48, 1, 2, 3, 0, 5, 11 };
- int usable_alignments = 10;
- int align1 = alignments[random() % (usable_alignments - 1)];
- int align2 = alignments[random() % (usable_alignments - 1)];
+ void BeginIterations() {
+ align1_index_ = 0;
+ align2_index_ = 0;
- ptr = glob_ptr + align1;
- ptr1 = glob_ptr1 + align1;
- ptr2 = glob_ptr2 + align2;
+ ResetPointers();
+ }
+
+ bool HasNextIteration() {
+ return (align1_index_ != (alignments_size - 1) || align2_index_ != (alignments_size - 1));
+ }
+
+ void NextIteration() {
+ if (align1_index_ == (alignments_size - 1) && align2_index_ == (alignments_size - 1)) {
+ return;
+ }
+
+ if (align1_index_ == (alignments_size - 1)) {
+ align1_index_ = 0;
+ align2_index_++;
+ } else {
+ align1_index_++;
+ }
+
+ ResetPointers();
}
const size_t MAX_LEN;
Character *ptr, *ptr1, *ptr2;
size_t n;
- int len[ITER + 1];
+ size_t len[ITER + 1];
private:
+ static size_t alignments[];
+ static size_t alignments_size;
Character *glob_ptr, *glob_ptr1, *glob_ptr2;
+ size_t align1_index_, align2_index_;
// Calculate input lengths and fill state.len with them.
// Test small lengths with more density than big ones. Manually push
@@ -186,26 +212,40 @@
n = 0;
len[n++] = 0;
for (size_t i = 1; i < ITER; ++i) {
- int l = (int) exp(log((double) MAX_LEN) * i / ITER);
+ size_t l = static_cast<size_t>(exp(log(static_cast<double>(MAX_LEN)) * i / ITER));
if (l != len[n - 1]) {
len[n++] = l;
}
}
len[n++] = MAX_LEN;
}
+
+ void ResetPointers() {
+ if (align1_index_ == alignments_size || align2_index_ == alignments_size) {
+ ptr = ptr1 = ptr2 = nullptr;
+ } else {
+ ptr = glob_ptr + alignments[align1_index_];
+ ptr1 = glob_ptr1 + alignments[align1_index_];
+ ptr2 = glob_ptr2 + alignments[align2_index_];
+ }
+ }
};
+template<class Character>
+size_t StringTestState<Character>::alignments[] = { 24, 32, 16, 48, 0, 1, 2, 3, 4, 5, 6, 7, 11 };
+
+template<class Character>
+size_t StringTestState<Character>::alignments_size = sizeof(alignments)/sizeof(size_t);
+
TEST(string, strcat) {
StringTestState<char> state(SMALL);
for (size_t i = 1; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
memset(state.ptr2, '\2', state.MAX_LEN);
state.ptr2[state.MAX_LEN - 1] = '\0';
memcpy(state.ptr, state.ptr2, 2 * state.MAX_LEN);
- memset(state.ptr1, random() & 255, state.len[i]);
+ memset(state.ptr1, 'L', state.len[i]);
state.ptr1[random() % state.len[i]] = '\0';
state.ptr1[state.len[i] - 1] = '\0';
@@ -378,13 +418,11 @@
}
TEST(string, strchr) {
- int seek_char = random() & 255;
+ int seek_char = 'R';
StringTestState<char> state(SMALL);
for (size_t i = 1; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
if (~seek_char > 0) {
memset(state.ptr1, ~seek_char, state.len[i]);
} else {
@@ -392,7 +430,7 @@
}
state.ptr1[state.len[i] - 1] = '\0';
- int pos = random() % state.MAX_LEN;
+ size_t pos = random() % state.MAX_LEN;
char* expected;
if (pos >= state.len[i] - 1) {
if (seek_char == 0) {
@@ -413,15 +451,13 @@
TEST(string, strcmp) {
StringTestState<char> state(SMALL);
for (size_t i = 1; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
memset(state.ptr1, 'v', state.MAX_LEN);
memset(state.ptr2, 'n', state.MAX_LEN);
state.ptr1[state.len[i] - 1] = '\0';
state.ptr2[state.len[i] - 1] = '\0';
- int pos = 1 + (random() % (state.MAX_LEN - 1));
+ size_t pos = 1 + (random() % (state.MAX_LEN - 1));
int actual;
int expected;
if (pos >= state.len[i] - 1) {
@@ -449,9 +485,7 @@
TEST(string, stpcpy) {
StringTestState<char> state(SMALL);
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
size_t pos = random() % state.MAX_LEN;
memset(state.ptr1, '\2', pos);
@@ -475,9 +509,7 @@
TEST(string, strcpy) {
StringTestState<char> state(SMALL);
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
size_t pos = random() % state.MAX_LEN;
memset(state.ptr1, '\2', pos);
@@ -503,14 +535,12 @@
#if defined(__BIONIC__)
StringTestState<char> state(SMALL);
for (size_t i = 0; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
memset(state.ptr2, '\2', state.MAX_LEN + state.len[i]);
state.ptr2[state.MAX_LEN - 1] = '\0';
memcpy(state.ptr, state.ptr2, state.MAX_LEN + state.len[i]);
- int pos = random() % state.MAX_LEN;
+ size_t pos = random() % state.MAX_LEN;
memset(state.ptr1, '\3', pos);
state.ptr1[pos] = '\0';
if (pos < state.len[i]) {
@@ -533,13 +563,8 @@
TEST(string, strlcpy) {
#if defined(__BIONIC__)
StringTestState<char> state(SMALL);
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
- int rand = random() & 255;
- if (rand < 1) {
- rand = 1;
- }
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+ int rand = 'O';
memset(state.ptr1, rand, state.MAX_LEN);
size_t pos = random() % state.MAX_LEN;
@@ -548,7 +573,7 @@
}
memcpy(state.ptr, state.ptr1, state.MAX_LEN);
- memset(state.ptr2, random() & 255, state.MAX_LEN);
+ memset(state.ptr2, 'I', state.MAX_LEN);
memcpy(state.ptr + state.MAX_LEN, state.ptr2, state.MAX_LEN);
if (pos > state.MAX_LEN - 1) {
@@ -570,14 +595,12 @@
TEST(string, strncat) {
StringTestState<char> state(SMALL);
for (size_t i = 1; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
memset(state.ptr2, '\2', state.MAX_LEN);
state.ptr2[state.MAX_LEN - 1] = '\0';
memcpy(state.ptr, state.ptr2, 2 * state.MAX_LEN);
- memset(state.ptr1, random() & 255, state.len[i]);
+ memset(state.ptr1, 'I', state.len[i]);
state.ptr1[random() % state.len[i]] = '\0';
state.ptr1[state.len[i] - 1] = '\0';
@@ -596,15 +619,13 @@
TEST(string, strncmp) {
StringTestState<char> state(SMALL);
for (size_t i = 1; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
memset(state.ptr1, 'v', state.MAX_LEN);
memset(state.ptr2, 'n', state.MAX_LEN);
state.ptr1[state.len[i] - 1] = '\0';
state.ptr2[state.len[i] - 1] = '\0';
- int pos = 1 + (random() % (state.MAX_LEN - 1));
+ size_t pos = 1 + (random() % (state.MAX_LEN - 1));
int actual;
int expected;
if (pos >= state.len[i] - 1) {
@@ -632,12 +653,8 @@
TEST(string, stpncpy) {
StringTestState<char> state(SMALL);
- for (size_t j = 0; j < ITER; j++) {
- state.NewIteration();
-
- // Choose a random value to fill the string, except \0 (string terminator),
- // or \1 (guarantees it's different from anything in ptr2).
- memset(state.ptr1, (random() % 254) + 2, state.MAX_LEN);
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+ memset(state.ptr1, 'J', state.MAX_LEN);
// Choose a random size for our src buffer.
size_t ptr1_len = random() % state.MAX_LEN;
state.ptr1[ptr1_len] = '\0';
@@ -671,12 +688,10 @@
TEST(string, strncpy) {
StringTestState<char> state(SMALL);
- for (size_t j = 0; j < ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
// Choose a random value to fill the string, except \0 (string terminator),
// or \1 (guarantees it's different from anything in ptr2).
- memset(state.ptr1, (random() % 254) + 2, state.MAX_LEN);
+ memset(state.ptr1, 'K', state.MAX_LEN);
// Choose a random size for our src buffer.
size_t ptr1_len = random() % state.MAX_LEN;
state.ptr1[ptr1_len] = '\0';
@@ -709,12 +724,10 @@
}
TEST(string, strrchr) {
- int seek_char = random() & 255;
+ int seek_char = 'M';
StringTestState<char> state(SMALL);
for (size_t i = 1; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
if (~seek_char > 0) {
memset(state.ptr1, ~seek_char, state.len[i]);
} else {
@@ -722,7 +735,7 @@
}
state.ptr1[state.len[i] - 1] = '\0';
- int pos = random() % state.MAX_LEN;
+ size_t pos = random() % state.MAX_LEN;
char* expected;
if (pos >= state.len[i] - 1) {
if (seek_char == 0) {
@@ -741,15 +754,13 @@
}
TEST(string, memchr) {
- int seek_char = random() & 255;
+ int seek_char = 'N';
StringTestState<char> state(SMALL);
for (size_t i = 0; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
memset(state.ptr1, ~seek_char, state.len[i]);
- int pos = random() % state.MAX_LEN;
+ size_t pos = random() % state.MAX_LEN;
char* expected;
if (pos >= state.len[i]) {
expected = NULL;
@@ -772,15 +783,13 @@
}
TEST(string, memrchr) {
- int seek_char = random() & 255;
+ int seek_char = 'P';
StringTestState<char> state(SMALL);
for (size_t i = 0; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
memset(state.ptr1, ~seek_char, state.len[i]);
- int pos = random() % state.MAX_LEN;
+ size_t pos = random() % state.MAX_LEN;
char* expected;
if (pos >= state.len[i]) {
expected = NULL;
@@ -797,11 +806,9 @@
TEST(string, memcmp) {
StringTestState<char> state(SMALL);
for (size_t i = 0; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
- int c1 = random() & 0xff;
- int c2 = random() & 0xff;
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+ int c1 = 'A';
+ int c2 = 'N';
memset(state.ptr1, c1, state.MAX_LEN);
memset(state.ptr2, c1, state.MAX_LEN);
@@ -820,9 +827,7 @@
StringTestState<wchar_t> state(SMALL);
for (size_t i = 0; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
long long mask = ((long long) 1 << 8 * sizeof(wchar_t)) - 1;
int c1 = rand() & mask;
int c2 = rand() & mask;
@@ -842,11 +847,9 @@
TEST(string, memcpy) {
StringTestState<char> state(LARGE);
- int rand = random() & 255;
+ int rand = 4;
for (size_t i = 0; i < state.n - 1; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
size_t pos = random() % (state.MAX_LEN - state.len[i]);
memset(state.ptr1, rand, state.len[i]);
@@ -864,11 +867,9 @@
TEST(string, memset) {
StringTestState<char> state(LARGE);
- char ch = random () & 255;
+ char ch = 'P';
for (size_t i = 0; i < state.n - 1; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
memset(state.ptr1, ~ch, state.MAX_LEN);
memcpy(state.ptr2, state.ptr1, state.MAX_LEN);
@@ -887,14 +888,12 @@
TEST(string, memmove) {
StringTestState<char> state(LARGE);
for (size_t i = 0; i < state.n - 1; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
- memset(state.ptr1, random() & 255, 2 * state.MAX_LEN);
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+ memset(state.ptr1, 'Q', 2 * state.MAX_LEN);
size_t pos = random() % (state.MAX_LEN - state.len[i]);
- memset(state.ptr1, random() & 255, state.len[i]);
+ memset(state.ptr1, 'R', state.len[i]);
memcpy(state.ptr2, state.ptr1, 2 * state.MAX_LEN);
memcpy(state.ptr, state.ptr1, state.len[i]);
memcpy(state.ptr1 + pos, state.ptr, state.len[i]);
@@ -920,8 +919,8 @@
for (int i = 0; i < 5; i++) {
char* ptr2 = glob_ptr2 + alignments[i];
- memset(ptr1, random() & 255, 2 * len);
- memset(ptr1, random() & 255, len);
+ memset(ptr1, 'S', 2 * len);
+ memset(ptr1, 'T', len);
memcpy(ptr2, ptr1, 2 * len);
memcpy(ptr, ptr1, len);
memcpy(ptr1 + pos, ptr, len);
@@ -987,11 +986,9 @@
TEST(string, bcopy) {
StringTestState<char> state(LARGE);
for (size_t i = 0; i < state.n; i++) {
- for (size_t j = 0; j < POS_ITER; j++) {
- state.NewIteration();
-
- memset(state.ptr1, random() & 255, state.MAX_LEN);
- memset(state.ptr1 + state.MAX_LEN, random() & 255, state.MAX_LEN);
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+ memset(state.ptr1, '4', state.MAX_LEN);
+ memset(state.ptr1 + state.MAX_LEN, 'a', state.MAX_LEN);
memcpy(state.ptr2, state.ptr1, 2 * state.MAX_LEN);
size_t start = random() % (2 * state.MAX_LEN - state.len[i]);
@@ -1005,10 +1002,8 @@
TEST(string, bzero) {
StringTestState<char> state(LARGE);
- for (size_t j = 0; j < ITER; j++) {
- state.NewIteration();
-
- memset(state.ptr1, random() & 255, state.MAX_LEN);
+ for (state.BeginIterations(); state.HasNextIteration(); state.NextIteration()) {
+ memset(state.ptr1, 'R', state.MAX_LEN);
size_t start = random() % state.MAX_LEN;
size_t end = start + random() % (state.MAX_LEN - start);
@@ -1287,3 +1282,22 @@
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 0bde024..38ef68a 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 @@
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 @@
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 241c4a0..c9ead8d 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 eca3c5e..c887f8a 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/wchar_test.cpp b/tests/wchar_test.cpp
index d02c4bf..760475f 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -489,3 +489,34 @@
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
+}