Merge "Rename DT_MIPS_RLD_MAP2 flag to DT_MIPS_RLD_MAP_REL"
diff --git a/libc/Android.bp b/libc/Android.bp
index 7c82695..c5a513c 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -82,7 +82,9 @@
stl: "none",
system_shared_libs: [],
- sanitize: ["never"],
+ sanitize: {
+ never: true,
+ },
native_coverage: false,
}
@@ -307,8 +309,6 @@
defaults: ["libc_defaults"],
srcs: [
"upstream-netbsd/common/lib/libc/stdlib/random.c",
- "upstream-netbsd/lib/libc/gen/ftw.c",
- "upstream-netbsd/lib/libc/gen/nftw.c",
"upstream-netbsd/lib/libc/gen/nice.c",
"upstream-netbsd/lib/libc/gen/popen.c",
"upstream-netbsd/lib/libc/gen/psignal.c",
@@ -414,6 +414,7 @@
"upstream-openbsd/lib/libc/locale/wcsxfrm.c",
"upstream-openbsd/lib/libc/locale/wctob.c",
"upstream-openbsd/lib/libc/locale/wctomb.c",
+ "upstream-openbsd/lib/libc/net/base64.c",
"upstream-openbsd/lib/libc/net/htonl.c",
"upstream-openbsd/lib/libc/net/htons.c",
"upstream-openbsd/lib/libc/net/inet_lnaof.c",
@@ -507,6 +508,7 @@
"upstream-openbsd/lib/libc/stdlib/atol.c",
"upstream-openbsd/lib/libc/stdlib/atoll.c",
"upstream-openbsd/lib/libc/stdlib/getenv.c",
+ "upstream-openbsd/lib/libc/stdlib/getsubopt.c",
"upstream-openbsd/lib/libc/stdlib/insque.c",
"upstream-openbsd/lib/libc/stdlib/imaxabs.c",
"upstream-openbsd/lib/libc/stdlib/imaxdiv.c",
@@ -1278,6 +1280,7 @@
"bionic/fpclassify.cpp",
"bionic/fsetxattr.cpp",
"bionic/ftruncate.cpp",
+ "bionic/ftw.cpp",
"bionic/futimens.cpp",
"bionic/getcwd.cpp",
"bionic/getdomainname.cpp",
@@ -1316,6 +1319,7 @@
"bionic/NetdClientDispatch.cpp",
"bionic/net_if.cpp",
"bionic/netinet_in.cpp",
+ "bionic/nl_types.cpp",
"bionic/open.cpp",
"bionic/pathconf.cpp",
"bionic/pause.cpp",
@@ -1348,12 +1352,17 @@
"bionic/sigdelset.cpp",
"bionic/sigemptyset.cpp",
"bionic/sigfillset.cpp",
+ "bionic/sighold.cpp",
+ "bionic/sigignore.cpp",
"bionic/sigismember.cpp",
"bionic/signal.cpp",
"bionic/signalfd.cpp",
+ "bionic/sigpause.cpp",
"bionic/sigpending.cpp",
"bionic/sigprocmask.cpp",
"bionic/sigqueue.cpp",
+ "bionic/sigrelse.cpp",
+ "bionic/sigset.cpp",
"bionic/sigsuspend.cpp",
"bionic/sigtimedwait.cpp",
"bionic/sigwait.cpp",
@@ -1367,6 +1376,7 @@
"bionic/strsignal.cpp",
"bionic/strtold.cpp",
"bionic/symlink.cpp",
+ "bionic/sync_file_range.cpp",
"bionic/sysinfo.cpp",
"bionic/syslog.cpp",
"bionic/sys_siglist.c",
@@ -1472,6 +1482,7 @@
// ========================================================
cc_library_static {
+ defaults: ["libc_defaults"],
arch: {
arm: {
srcs: ["arch-arm/syscalls/**/*.S"],
@@ -1912,7 +1923,7 @@
"crt_defaults",
"crt_so_defaults",
],
- deps: [
+ objs: [
"crtbegin_so1",
"crtbrand",
],
@@ -1970,7 +1981,7 @@
cc_object {
name: "crtbegin_static",
- deps: [
+ objs: [
"crtbegin_static1",
"crtbrand",
],
@@ -2016,7 +2027,7 @@
cc_object {
name: "crtbegin_dynamic",
- deps: [
+ objs: [
"crtbegin_dynamic1",
"crtbrand",
],
diff --git a/libc/Android.mk b/libc/Android.mk
index 631de5e..02682af 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -107,6 +107,7 @@
bionic/fpclassify.cpp \
bionic/fsetxattr.cpp \
bionic/ftruncate.cpp \
+ bionic/ftw.cpp \
bionic/futimens.cpp \
bionic/getcwd.cpp \
bionic/getdomainname.cpp \
@@ -145,6 +146,7 @@
bionic/NetdClientDispatch.cpp \
bionic/net_if.cpp \
bionic/netinet_in.cpp \
+ bionic/nl_types.cpp \
bionic/open.cpp \
bionic/pathconf.cpp \
bionic/pause.cpp \
@@ -287,8 +289,6 @@
libc_upstream_netbsd_src_files := \
upstream-netbsd/common/lib/libc/stdlib/random.c \
- upstream-netbsd/lib/libc/gen/ftw.c \
- upstream-netbsd/lib/libc/gen/nftw.c \
upstream-netbsd/lib/libc/gen/nice.c \
upstream-netbsd/lib/libc/gen/popen.c \
upstream-netbsd/lib/libc/gen/psignal.c \
@@ -406,6 +406,7 @@
upstream-openbsd/lib/libc/locale/wcsxfrm.c \
upstream-openbsd/lib/libc/locale/wctob.c \
upstream-openbsd/lib/libc/locale/wctomb.c \
+ upstream-openbsd/lib/libc/net/base64.c \
upstream-openbsd/lib/libc/net/htonl.c \
upstream-openbsd/lib/libc/net/htons.c \
upstream-openbsd/lib/libc/net/inet_lnaof.c \
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 87f600b..e530293 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -322,6 +322,8 @@
ssize_t process_vm_readv(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long) all
ssize_t process_vm_writev(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long) all
+int quotactl(int, const char*, int, char*) all
+
int __set_tid_address:set_tid_address(int*) all
int setfsgid(gid_t) all
diff --git a/libc/arch-arm/syscalls/quotactl.S b/libc/arch-arm/syscalls/quotactl.S
new file mode 100644
index 0000000..831d229
--- /dev/null
+++ b/libc/arch-arm/syscalls/quotactl.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(quotactl)
+ mov ip, r7
+ ldr r7, =__NR_quotactl
+ swi #0
+ mov r7, ip
+ cmn r0, #(MAX_ERRNO + 1)
+ bxls lr
+ neg r0, r0
+ b __set_errno_internal
+END(quotactl)
diff --git a/libc/arch-arm64/syscalls/quotactl.S b/libc/arch-arm64/syscalls/quotactl.S
new file mode 100644
index 0000000..b67d47e
--- /dev/null
+++ b/libc/arch-arm64/syscalls/quotactl.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(quotactl)
+ mov x8, __NR_quotactl
+ svc #0
+
+ cmn x0, #(MAX_ERRNO + 1)
+ cneg x0, x0, hi
+ b.hi __set_errno_internal
+
+ ret
+END(quotactl)
diff --git a/libc/arch-mips/syscalls/quotactl.S b/libc/arch-mips/syscalls/quotactl.S
new file mode 100644
index 0000000..fef336a
--- /dev/null
+++ b/libc/arch-mips/syscalls/quotactl.S
@@ -0,0 +1,19 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(quotactl)
+ .set noreorder
+ .cpload t9
+ li v0, __NR_quotactl
+ syscall
+ bnez a3, 1f
+ move a0, v0
+ j ra
+ nop
+1:
+ la t9,__set_errno_internal
+ j t9
+ nop
+ .set reorder
+END(quotactl)
diff --git a/libc/arch-mips64/syscalls/quotactl.S b/libc/arch-mips64/syscalls/quotactl.S
new file mode 100644
index 0000000..861947c
--- /dev/null
+++ b/libc/arch-mips64/syscalls/quotactl.S
@@ -0,0 +1,25 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(quotactl)
+ .set push
+ .set noreorder
+ li v0, __NR_quotactl
+ 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_internal
+ .cpreturn
+ j t9
+ move ra, t0
+ .set pop
+END(quotactl)
diff --git a/libc/arch-x86/syscalls/quotactl.S b/libc/arch-x86/syscalls/quotactl.S
new file mode 100644
index 0000000..326cf87
--- /dev/null
+++ b/libc/arch-x86/syscalls/quotactl.S
@@ -0,0 +1,44 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(quotactl)
+ pushl %ebx
+ .cfi_def_cfa_offset 8
+ .cfi_rel_offset ebx, 0
+ pushl %ecx
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset ecx, 0
+ pushl %edx
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset edx, 0
+ pushl %esi
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset esi, 0
+
+ call __kernel_syscall
+ pushl %eax
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset eax, 0
+
+ mov 24(%esp), %ebx
+ mov 28(%esp), %ecx
+ mov 32(%esp), %edx
+ mov 36(%esp), %esi
+ movl $__NR_quotactl, %eax
+ call *(%esp)
+ addl $4, %esp
+
+ cmpl $-MAX_ERRNO, %eax
+ jb 1f
+ negl %eax
+ pushl %eax
+ call __set_errno_internal
+ addl $4, %esp
+1:
+ popl %esi
+ popl %edx
+ popl %ecx
+ popl %ebx
+ ret
+END(quotactl)
diff --git a/libc/arch-x86_64/syscalls/quotactl.S b/libc/arch-x86_64/syscalls/quotactl.S
new file mode 100644
index 0000000..427358a
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/quotactl.S
@@ -0,0 +1,16 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(quotactl)
+ movq %rcx, %r10
+ movl $__NR_quotactl, %eax
+ syscall
+ cmpq $-MAX_ERRNO, %rax
+ jb 1f
+ negl %eax
+ movl %eax, %edi
+ call __set_errno_internal
+1:
+ ret
+END(quotactl)
diff --git a/libc/bionic/clock.cpp b/libc/bionic/clock.cpp
index 053e9e7..fda0708 100644
--- a/libc/bionic/clock.cpp
+++ b/libc/bionic/clock.cpp
@@ -26,9 +26,9 @@
* SUCH DAMAGE.
*/
-#include <time.h>
-#include <sys/sysconf.h>
#include <sys/times.h>
+#include <time.h>
+#include <unistd.h>
#include "private/bionic_constants.h"
diff --git a/libc/bionic/ftw.cpp b/libc/bionic/ftw.cpp
new file mode 100644
index 0000000..2123619
--- /dev/null
+++ b/libc/bionic/ftw.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <errno.h>
+#include <fts.h>
+#include <ftw.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static int do_nftw(const char *path,
+ int (*ftw_fn)(const char*, const struct stat*, int),
+ int (*nftw_fn)(const char*, const struct stat*, int, FTW*),
+ int nfds,
+ int nftw_flags) {
+ // TODO: nfds is currently unused.
+ if (nfds < 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Translate to fts_open options.
+ int fts_options = FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR;
+ if (nftw_fn) {
+ fts_options = FTS_COMFOLLOW | ((nftw_flags & FTW_PHYS) ? FTS_PHYSICAL : FTS_LOGICAL);
+ if (!(nftw_flags & FTW_CHDIR)) fts_options |= FTS_NOCHDIR;
+ if (nftw_flags & FTW_MOUNT) fts_options |= FTS_XDEV;
+ }
+ bool postorder = (nftw_flags & FTW_DEPTH) != 0;
+
+ // Call fts_open.
+ char* const paths[2] = { const_cast<char*>(path), nullptr };
+ FTS* fts = fts_open(paths, fts_options, nullptr);
+ if (fts == nullptr) {
+ return -1;
+ }
+
+ // Translate fts_read results into ftw/nftw callbacks.
+ int error = 0;
+ FTSENT* cur;
+ while (error == 0 && (cur = fts_read(fts)) != nullptr) {
+ int fn_flag;
+ switch (cur->fts_info) {
+ case FTS_D:
+ // In the postorder case, we'll translate FTS_DP to FTW_DP later.
+ // In the can't-access case, we'll translate FTS_DNR to FTW_DNR later.
+ if (postorder || access(cur->fts_path, R_OK) == -1) continue;
+ fn_flag = FTW_D;
+ break;
+ case FTS_DNR:
+ fn_flag = FTW_DNR;
+ break;
+ case FTS_DP:
+ if (!postorder) continue;
+ fn_flag = FTW_DP;
+ break;
+ case FTS_F:
+ case FTS_DEFAULT:
+ fn_flag = FTW_F;
+ break;
+ case FTS_NS:
+ case FTS_NSOK:
+ fn_flag = FTW_NS;
+ break;
+ case FTS_SL:
+ fn_flag = FTW_SL;
+ break;
+ case FTS_SLNONE:
+ fn_flag = (nftw_fn != nullptr) ? FTW_SLN : FTW_NS;
+ break;
+ case FTS_DC:
+ errno = ELOOP;
+ error = -1;
+ continue;
+ default:
+ error = -1;
+ continue;
+ }
+
+ // Call the appropriate function.
+ if (nftw_fn != nullptr) {
+ FTW ftw;
+ ftw.base = cur->fts_pathlen - cur->fts_namelen;
+ ftw.level = cur->fts_level;
+ error = nftw_fn(cur->fts_path, cur->fts_statp, fn_flag, &ftw);
+ } else {
+ error = ftw_fn(cur->fts_path, cur->fts_statp, fn_flag);
+ }
+ }
+
+ int saved_errno = errno;
+ if (fts_close(fts) != 0 && error == 0) {
+ error = -1;
+ } else {
+ errno = saved_errno;
+ }
+ return error;
+}
+
+int ftw(const char* path, int (*ftw_fn)(const char*, const struct stat*, int), int nfds) {
+ return do_nftw(path, ftw_fn, nullptr, nfds, 0);
+}
+
+int nftw(const char* path, int (*nftw_fn)(const char*, const struct stat*, int, FTW*),
+ int nfds, int nftw_flags) {
+ return do_nftw(path, nullptr, nftw_fn, nfds, nftw_flags);
+}
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index 1cabab4..d75b94d 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -312,27 +312,34 @@
}
}
+// oem_XXXX -> uid
+// Supported ranges:
+// AID_OEM_RESERVED_START to AID_OEM_RESERVED_END (2900-2999)
+// AID_OEM_RESERVED_2_START to AID_OEM_RESERVED_2_END (5000-5999)
+// Check OEM id is within range.
+static bool is_oem_id(id_t id) {
+ return (((id >= AID_OEM_RESERVED_START) && (id <= AID_OEM_RESERVED_END)) ||
+ ((id >= AID_OEM_RESERVED_2_START) && (id <= AID_OEM_RESERVED_2_END)));
+}
+
// Translate an OEM name to the corresponding user/group id.
-// oem_XXX -> AID_OEM_RESERVED_2_START + XXX, iff XXX is within range.
static id_t oem_id_from_name(const char* name) {
unsigned int id;
if (sscanf(name, "oem_%u", &id) != 1) {
return 0;
}
- // Check OEM id is within range.
- if (id > (AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START)) {
+ if (!is_oem_id(id)) {
return 0;
}
- return AID_OEM_RESERVED_2_START + static_cast<id_t>(id);
+ return static_cast<id_t>(id);
}
static passwd* oem_id_to_passwd(uid_t uid, passwd_state_t* state) {
- if (uid < AID_OEM_RESERVED_2_START || uid > AID_OEM_RESERVED_2_END) {
+ if (!is_oem_id(uid)) {
return NULL;
}
- snprintf(state->name_buffer_, sizeof(state->name_buffer_), "oem_%u",
- uid - AID_OEM_RESERVED_2_START);
+ snprintf(state->name_buffer_, sizeof(state->name_buffer_), "oem_%u", uid);
snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
@@ -346,12 +353,12 @@
}
static group* oem_id_to_group(gid_t gid, group_state_t* state) {
- if (gid < AID_OEM_RESERVED_2_START || gid > AID_OEM_RESERVED_2_END) {
+ if (!is_oem_id(gid)) {
return NULL;
}
snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_),
- "oem_%u", gid - AID_OEM_RESERVED_2_START);
+ "oem_%u", gid);
group* gr = &state->group_;
gr->gr_name = state->group_name_buffer_;
diff --git a/libc/bionic/nl_types.cpp b/libc/bionic/nl_types.cpp
new file mode 100644
index 0000000..2cde591
--- /dev/null
+++ b/libc/bionic/nl_types.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <nl_types.h>
+
+#include <errno.h>
+
+nl_catd catopen(const char*, int) {
+ return reinterpret_cast<nl_catd>(-1);
+}
+
+char* catgets(nl_catd, int, int, const char* message) {
+ return const_cast<char*>(message);
+}
+
+int catclose(nl_catd) {
+ // Since we didn't hand out a valid nl_catd, you can't be returning one to us.
+ errno = EBADF;
+ return -1;
+}
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index d419fb1..a0a0809 100644
--- a/libc/bionic/strerror_r.cpp
+++ b/libc/bionic/strerror_r.cpp
@@ -31,7 +31,7 @@
static const Pair _sys_error_strings[] = {
#define __BIONIC_ERRDEF(x,y,z) { x, z },
-#include <sys/_errdefs.h>
+#include "private/bionic_errdefs.h"
{ 0, NULL }
};
@@ -41,7 +41,7 @@
static const Pair _sys_signal_strings[] = {
#define __BIONIC_SIGDEF(signal_number, signal_description) { signal_number, signal_description },
-#include <sys/_sigdefs.h>
+#include "private/bionic_sigdefs.h"
{ 0, NULL }
};
diff --git a/libc/bionic/sys_siglist.c b/libc/bionic/sys_siglist.c
index 3cfddbf..8e33d64 100644
--- a/libc/bionic/sys_siglist.c
+++ b/libc/bionic/sys_siglist.c
@@ -30,5 +30,5 @@
const char* const sys_siglist[NSIG] = {
#define __BIONIC_SIGDEF(signal_number, signal_description) [ signal_number ] = signal_description,
-#include <sys/_sigdefs.h>
+#include "private/bionic_sigdefs.h"
};
diff --git a/libc/bionic/sys_signame.c b/libc/bionic/sys_signame.c
index e1286f2..5158b83 100644
--- a/libc/bionic/sys_signame.c
+++ b/libc/bionic/sys_signame.c
@@ -30,5 +30,5 @@
const char* const sys_signame[NSIG] = {
#define __BIONIC_SIGDEF(signal_number, unused) [ signal_number ] = #signal_number + 3,
-#include <sys/_sigdefs.h>
+#include "private/bionic_sigdefs.h"
};
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index cff6288..7be0ab7 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -34,7 +34,6 @@
#include <stdio.h> // For FOPEN_MAX.
#include <sys/auxv.h>
#include <sys/resource.h>
-#include <sys/sysconf.h>
#include <sys/sysinfo.h>
#include <time.h>
#include <unistd.h>
diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h
index 2d2f096..b230cef 100644
--- a/libc/include/android/api-level.h
+++ b/libc/include/android/api-level.h
@@ -33,6 +33,8 @@
* Magic version number for a current development build, which has
* not yet turned into an official release.
*/
+#ifndef __ANDROID_API__
#define __ANDROID_API__ 10000
+#endif
#endif /* ANDROID_API_LEVEL_H */
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index d5ec386..6e32b68 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -17,6 +17,7 @@
#ifndef __ANDROID_DLEXT_H__
#define __ANDROID_DLEXT_H__
+#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/cdefs.h>
diff --git a/libc/include/android/legacy_errno_inlines.h b/libc/include/android/legacy_errno_inlines.h
index 71096fc..93cba1f 100644
--- a/libc/include/android/legacy_errno_inlines.h
+++ b/libc/include/android/legacy_errno_inlines.h
@@ -29,8 +29,11 @@
#ifndef _ANDROID_LEGACY_ERRNO_INLINES_H
#define _ANDROID_LEGACY_ERRNO_INLINES_H
+#include <errno.h>
#include <sys/cdefs.h>
+#if __ANDROID_API__ < 21
+
__BEGIN_DECLS
static __inline int __attribute__((deprecated)) __set_errno(int n) {
@@ -40,4 +43,5 @@
__END_DECLS
+#endif
#endif /* _ANDROID_LEGACY_ERRNO_INLINES_H */
diff --git a/libc/include/android/legacy_signal_inlines.h b/libc/include/android/legacy_signal_inlines.h
index 1b6e687..bf895da 100644
--- a/libc/include/android/legacy_signal_inlines.h
+++ b/libc/include/android/legacy_signal_inlines.h
@@ -29,14 +29,18 @@
#ifndef _ANDROID_LEGACY_SIGNAL_INLINES_H_
#define _ANDROID_LEGACY_SIGNAL_INLINES_H_
+#include <errno.h>
+#include <signal.h>
#include <string.h>
#include <sys/cdefs.h>
+#if __ANDROID_API__ < 21
+
__BEGIN_DECLS
extern sighandler_t bsd_signal(int signum, sighandler_t handler);
-static __inline int sigismember(sigset_t *set, int signum) {
+static __inline int sigismember(const sigset_t *set, int signum) {
/* Signal numbers start at 1, but bit positions start at 0. */
int bit = signum - 1;
const unsigned long *local_set = (const unsigned long *)set;
@@ -95,4 +99,5 @@
__END_DECLS
+#endif
#endif /* _ANDROID_LEGACY_SIGNAL_INLINES_H_ */
diff --git a/libc/include/android/legacy_stdlib_inlines.h b/libc/include/android/legacy_stdlib_inlines.h
index 58a2a9e..93554e5 100644
--- a/libc/include/android/legacy_stdlib_inlines.h
+++ b/libc/include/android/legacy_stdlib_inlines.h
@@ -29,8 +29,11 @@
#ifndef _ANDROID_LEGACY_STDLIB_INLINES_H_
#define _ANDROID_LEGACY_STDLIB_INLINES_H_
+#include <stdlib.h>
#include <sys/cdefs.h>
+#if __ANDROID_API__ < 21
+
__BEGIN_DECLS
static __inline float strtof(const char *nptr, char **endptr) {
@@ -61,4 +64,5 @@
__END_DECLS
+#endif
#endif /* _ANDROID_LEGACY_STDLIB_INLINES_H_ */
diff --git a/libc/include/android/legacy_sys_atomics_inlines.h b/libc/include/android/legacy_sys_atomics_inlines.h
index 85cbade..3314e35 100644
--- a/libc/include/android/legacy_sys_atomics_inlines.h
+++ b/libc/include/android/legacy_sys_atomics_inlines.h
@@ -31,6 +31,8 @@
#include <sys/cdefs.h>
+#if __ANDROID_API__ < 21
+
__BEGIN_DECLS
/* Note: atomic operations that were exported by the C library didn't
@@ -69,4 +71,5 @@
__END_DECLS
+#endif
#endif /* _ANDROID_LEGACY_SYS_ATOMICS_INLINES_H_ */
diff --git a/libc/include/android/legacy_sys_stat_inlines.h b/libc/include/android/legacy_sys_stat_inlines.h
index f6d3c0f..c08edfa 100644
--- a/libc/include/android/legacy_sys_stat_inlines.h
+++ b/libc/include/android/legacy_sys_stat_inlines.h
@@ -30,6 +30,9 @@
#define _ANDROID_LEGACY_SYS_STAT_INLINES_H_
#include <sys/cdefs.h>
+#include <sys/stat.h>
+
+#if __ANDROID_API__ < 21
__BEGIN_DECLS
@@ -39,4 +42,5 @@
__END_DECLS
+#endif
#endif /* _ANDROID_LEGACY_SYS_STAT_INLINES_H_ */
diff --git a/libc/include/android/legacy_termios_inlines.h b/libc/include/android/legacy_termios_inlines.h
index fb61f27..41ea955 100644
--- a/libc/include/android/legacy_termios_inlines.h
+++ b/libc/include/android/legacy_termios_inlines.h
@@ -34,6 +34,8 @@
#include <sys/ioctl.h>
#include <sys/types.h>
+#if __ANDROID_API__ < 21
+
__BEGIN_DECLS
static __inline int tcgetattr(int fd, struct termios *s) {
@@ -90,4 +92,5 @@
__END_DECLS
+#endif
#endif /* _ANDROID_LEGACY_TERMIOS_INLINES_H_ */
diff --git a/libc/include/bits/fcntl.h b/libc/include/bits/fcntl.h
new file mode 100644
index 0000000..90f933c
--- /dev/null
+++ b/libc/include/bits/fcntl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BITS_FCNTL_H_
+#define _BITS_FCNTL_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int fcntl(int, int, ...);
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/bits/getopt.h b/libc/include/bits/getopt.h
new file mode 100644
index 0000000..7153d48
--- /dev/null
+++ b/libc/include/bits/getopt.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BITS_GETOPT_H_
+#define _BITS_GETOPT_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+int getopt(int, char * const [], const char *);
+
+extern char *optarg; /* getopt(3) external variables */
+extern int optind, opterr, optopt;
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/bits/ioctl.h b/libc/include/bits/ioctl.h
new file mode 100644
index 0000000..788a4f7
--- /dev/null
+++ b/libc/include/bits/ioctl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BITS_IOCTL_H_
+#define _BITS_IOCTL_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int ioctl(int, int, ...);
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/bits/lockf.h b/libc/include/bits/lockf.h
index d814807..a0ba19d 100644
--- a/libc/include/bits/lockf.h
+++ b/libc/include/bits/lockf.h
@@ -30,6 +30,7 @@
#define _BITS_LOCKF_H_
#include <sys/cdefs.h>
+#include <sys/types.h>
#define F_ULOCK 0
#define F_LOCK 1
diff --git a/libc/include/bits/strcasecmp.h b/libc/include/bits/strcasecmp.h
new file mode 100644
index 0000000..124f5cd
--- /dev/null
+++ b/libc/include/bits/strcasecmp.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BITS_STRCASECMP_H_
+#define _BITS_STRCASECMP_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <xlocale.h>
+
+__BEGIN_DECLS
+
+int strcasecmp(const char*, const char*) __purefunc;
+int strcasecmp_l(const char*, const char*, locale_t) __purefunc;
+int strncasecmp(const char*, const char*, size_t) __purefunc;
+int strncasecmp_l(const char*, const char*, size_t, locale_t) __purefunc;
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/bits/sysconf.h b/libc/include/bits/sysconf.h
new file mode 100644
index 0000000..2cbbb11
--- /dev/null
+++ b/libc/include/bits/sysconf.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BITS_SYSCONF_H_
+#define _BITS_SYSCONF_H_
+
+#include <sys/cdefs.h>
+
+/* as listed by Posix sysconf() description */
+/* most of these will return -1 and ENOSYS */
+
+#define _SC_ARG_MAX 0x0000
+#define _SC_BC_BASE_MAX 0x0001
+#define _SC_BC_DIM_MAX 0x0002
+#define _SC_BC_SCALE_MAX 0x0003
+#define _SC_BC_STRING_MAX 0x0004
+#define _SC_CHILD_MAX 0x0005
+#define _SC_CLK_TCK 0x0006
+#define _SC_COLL_WEIGHTS_MAX 0x0007
+#define _SC_EXPR_NEST_MAX 0x0008
+#define _SC_LINE_MAX 0x0009
+#define _SC_NGROUPS_MAX 0x000a
+#define _SC_OPEN_MAX 0x000b
+#define _SC_PASS_MAX 0x000c
+#define _SC_2_C_BIND 0x000d
+#define _SC_2_C_DEV 0x000e
+#define _SC_2_C_VERSION 0x000f /* Obsolescent in POSIX.1-2008, TODO: remove it. */
+#define _SC_2_CHAR_TERM 0x0010
+#define _SC_2_FORT_DEV 0x0011
+#define _SC_2_FORT_RUN 0x0012
+#define _SC_2_LOCALEDEF 0x0013
+#define _SC_2_SW_DEV 0x0014
+#define _SC_2_UPE 0x0015
+#define _SC_2_VERSION 0x0016
+#define _SC_JOB_CONTROL 0x0017
+#define _SC_SAVED_IDS 0x0018
+#define _SC_VERSION 0x0019
+#define _SC_RE_DUP_MAX 0x001a
+#define _SC_STREAM_MAX 0x001b
+#define _SC_TZNAME_MAX 0x001c
+#define _SC_XOPEN_CRYPT 0x001d
+#define _SC_XOPEN_ENH_I18N 0x001e
+#define _SC_XOPEN_SHM 0x001f
+#define _SC_XOPEN_VERSION 0x0020
+#define _SC_XOPEN_XCU_VERSION 0x0021 /* Obsolescent in POSIX.1-2008, TODO: remove it. */
+#define _SC_XOPEN_REALTIME 0x0022
+#define _SC_XOPEN_REALTIME_THREADS 0x0023
+#define _SC_XOPEN_LEGACY 0x0024
+#define _SC_ATEXIT_MAX 0x0025
+#define _SC_IOV_MAX 0x0026
+#define _SC_PAGESIZE 0x0027
+#define _SC_PAGE_SIZE 0x0028
+#define _SC_XOPEN_UNIX 0x0029
+#define _SC_XBS5_ILP32_OFF32 0x002a /* Obsolescent in POSIX.1-2008, TODO: remove it. */
+#define _SC_XBS5_ILP32_OFFBIG 0x002b /* Obsolescent in POSIX.1-2008, TODO: remove it. */
+#define _SC_XBS5_LP64_OFF64 0x002c /* Obsolescent in POSIX.1-2008, TODO: remove it. */
+#define _SC_XBS5_LPBIG_OFFBIG 0x002d /* Obsolescent in POSIX.1-2008, TODO: remove it. */
+#define _SC_AIO_LISTIO_MAX 0x002e
+#define _SC_AIO_MAX 0x002f
+#define _SC_AIO_PRIO_DELTA_MAX 0x0030
+#define _SC_DELAYTIMER_MAX 0x0031
+#define _SC_MQ_OPEN_MAX 0x0032
+#define _SC_MQ_PRIO_MAX 0x0033
+#define _SC_RTSIG_MAX 0x0034
+#define _SC_SEM_NSEMS_MAX 0x0035
+#define _SC_SEM_VALUE_MAX 0x0036
+#define _SC_SIGQUEUE_MAX 0x0037
+#define _SC_TIMER_MAX 0x0038
+#define _SC_ASYNCHRONOUS_IO 0x0039
+#define _SC_FSYNC 0x003a
+#define _SC_MAPPED_FILES 0x003b
+#define _SC_MEMLOCK 0x003c
+#define _SC_MEMLOCK_RANGE 0x003d
+#define _SC_MEMORY_PROTECTION 0x003e
+#define _SC_MESSAGE_PASSING 0x003f
+#define _SC_PRIORITIZED_IO 0x0040
+#define _SC_PRIORITY_SCHEDULING 0x0041
+#define _SC_REALTIME_SIGNALS 0x0042
+#define _SC_SEMAPHORES 0x0043
+#define _SC_SHARED_MEMORY_OBJECTS 0x0044
+#define _SC_SYNCHRONIZED_IO 0x0045
+#define _SC_TIMERS 0x0046
+#define _SC_GETGR_R_SIZE_MAX 0x0047
+#define _SC_GETPW_R_SIZE_MAX 0x0048
+#define _SC_LOGIN_NAME_MAX 0x0049
+#define _SC_THREAD_DESTRUCTOR_ITERATIONS 0x004a
+#define _SC_THREAD_KEYS_MAX 0x004b
+#define _SC_THREAD_STACK_MIN 0x004c
+#define _SC_THREAD_THREADS_MAX 0x004d
+#define _SC_TTY_NAME_MAX 0x004e
+
+#define _SC_THREADS 0x004f
+#define _SC_THREAD_ATTR_STACKADDR 0x0050
+#define _SC_THREAD_ATTR_STACKSIZE 0x0051
+#define _SC_THREAD_PRIORITY_SCHEDULING 0x0052
+#define _SC_THREAD_PRIO_INHERIT 0x0053
+#define _SC_THREAD_PRIO_PROTECT 0x0054
+#define _SC_THREAD_SAFE_FUNCTIONS 0x0055
+
+#define _SC_NPROCESSORS_CONF 0x0060
+#define _SC_NPROCESSORS_ONLN 0x0061
+#define _SC_PHYS_PAGES 0x0062
+#define _SC_AVPHYS_PAGES 0x0063
+#define _SC_MONOTONIC_CLOCK 0x0064
+
+#define _SC_2_PBS 0x0065
+#define _SC_2_PBS_ACCOUNTING 0x0066
+#define _SC_2_PBS_CHECKPOINT 0x0067
+#define _SC_2_PBS_LOCATE 0x0068
+#define _SC_2_PBS_MESSAGE 0x0069
+#define _SC_2_PBS_TRACK 0x006a
+#define _SC_ADVISORY_INFO 0x006b
+#define _SC_BARRIERS 0x006c
+#define _SC_CLOCK_SELECTION 0x006d
+#define _SC_CPUTIME 0x006e
+#define _SC_HOST_NAME_MAX 0x006f
+#define _SC_IPV6 0x0070
+#define _SC_RAW_SOCKETS 0x0071
+#define _SC_READER_WRITER_LOCKS 0x0072
+#define _SC_REGEXP 0x0073
+#define _SC_SHELL 0x0074
+#define _SC_SPAWN 0x0075
+#define _SC_SPIN_LOCKS 0x0076
+#define _SC_SPORADIC_SERVER 0x0077
+#define _SC_SS_REPL_MAX 0x0078
+#define _SC_SYMLOOP_MAX 0x0079
+#define _SC_THREAD_CPUTIME 0x007a
+#define _SC_THREAD_PROCESS_SHARED 0x007b
+#define _SC_THREAD_ROBUST_PRIO_INHERIT 0x007c
+#define _SC_THREAD_ROBUST_PRIO_PROTECT 0x007d
+#define _SC_THREAD_SPORADIC_SERVER 0x007e
+#define _SC_TIMEOUTS 0x007f
+#define _SC_TRACE 0x0080
+#define _SC_TRACE_EVENT_FILTER 0x0081
+#define _SC_TRACE_EVENT_NAME_MAX 0x0082
+#define _SC_TRACE_INHERIT 0x0083
+#define _SC_TRACE_LOG 0x0084
+#define _SC_TRACE_NAME_MAX 0x0085
+#define _SC_TRACE_SYS_MAX 0x0086
+#define _SC_TRACE_USER_EVENT_MAX 0x0087
+#define _SC_TYPED_MEMORY_OBJECTS 0x0088
+#define _SC_V7_ILP32_OFF32 0x0089
+#define _SC_V7_ILP32_OFFBIG 0x008a
+#define _SC_V7_LP64_OFF64 0x008b
+#define _SC_V7_LPBIG_OFFBIG 0x008c
+#define _SC_XOPEN_STREAMS 0x008d
+#define _SC_XOPEN_UUCP 0x008e
+
+#define _SC_LEVEL1_ICACHE_SIZE 0x008f
+#define _SC_LEVEL1_ICACHE_ASSOC 0x0090
+#define _SC_LEVEL1_ICACHE_LINESIZE 0x0091
+#define _SC_LEVEL1_DCACHE_SIZE 0x0092
+#define _SC_LEVEL1_DCACHE_ASSOC 0x0093
+#define _SC_LEVEL1_DCACHE_LINESIZE 0x0094
+#define _SC_LEVEL2_CACHE_SIZE 0x0095
+#define _SC_LEVEL2_CACHE_ASSOC 0x0096
+#define _SC_LEVEL2_CACHE_LINESIZE 0x0097
+#define _SC_LEVEL3_CACHE_SIZE 0x0098
+#define _SC_LEVEL3_CACHE_ASSOC 0x0099
+#define _SC_LEVEL3_CACHE_LINESIZE 0x009a
+#define _SC_LEVEL4_CACHE_SIZE 0x009b
+#define _SC_LEVEL4_CACHE_ASSOC 0x009c
+#define _SC_LEVEL4_CACHE_LINESIZE 0x009d
+
+__BEGIN_DECLS
+
+long sysconf(int __name);
+
+__END_DECLS
+
+#endif /* _SYS_SYSCONF_H_ */
diff --git a/libc/include/errno.h b/libc/include/errno.h
index 82f4b42..2ff1369 100644
--- a/libc/include/errno.h
+++ b/libc/include/errno.h
@@ -46,10 +46,8 @@
/* a macro expanding to the errno l-value */
#define errno (*__errno())
-#if __ANDROID_API__ < 21
-#include <android/legacy_errno_inlines.h>
-#endif
-
__END_DECLS
+#include <android/legacy_errno_inlines.h>
+
#endif /* _ERRNO_H */
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 9d15e92..013d72c 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -36,6 +36,8 @@
#include <linux/stat.h>
#include <linux/uio.h>
+#include <bits/fcntl.h>
+
#if defined(__USE_GNU) || defined(__USE_BSD)
#include <bits/lockf.h>
#endif
@@ -63,14 +65,12 @@
extern int creat(const char*, mode_t);
extern int creat64(const char*, mode_t);
-extern int fcntl(int, int, ...);
extern int openat(int, const char*, int, ...);
extern int openat64(int, const char*, int, ...);
extern int open(const char*, int, ...);
extern int open64(const char*, int, ...);
extern ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int);
extern ssize_t tee(int, int, size_t, unsigned int);
-extern int unlinkat(int, const char*, int);
extern ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int);
#if defined(__USE_FILE_OFFSET64)
diff --git a/libc/include/getopt.h b/libc/include/getopt.h
index 4451941..46d2eb7 100644
--- a/libc/include/getopt.h
+++ b/libc/include/getopt.h
@@ -35,9 +35,10 @@
#include <sys/cdefs.h>
+#include <bits/getopt.h>
+
/*
* GNU-like getopt_long()/getopt_long_only() with 4.4BSD optreset extension.
- * getopt() is declared here too for GNU programs.
*/
#define no_argument 0
#define required_argument 1
@@ -62,13 +63,7 @@
const struct option *, int *);
int getopt_long_only(int, char * const *, const char *,
const struct option *, int *);
-#ifndef _GETOPT_DECLARED
-#define _GETOPT_DECLARED
-int getopt(int, char * const [], const char *);
-extern char *optarg; /* getopt(3) external variables */
-extern int optind, opterr, optopt;
-#endif
#ifndef _OPTRESET_DECLARED
#define _OPTRESET_DECLARED
extern int optreset; /* getopt(3) external variable */
diff --git a/libc/include/math.h b/libc/include/math.h
index 8e193cb..203968a 100644
--- a/libc/include/math.h
+++ b/libc/include/math.h
@@ -20,12 +20,6 @@
#include <sys/cdefs.h>
#include <limits.h>
-#if !defined(__BIONIC_NO_MATH_INLINES)
-#define __BIONIC_MATH_INLINE(__def) extern __inline__ __always_inline __attribute__((gnu_inline)) __attribute__((__artificial__)) __def
-#else
-#define __BIONIC_MATH_INLINE(__def)
-#endif
-
__BEGIN_DECLS
#pragma GCC visibility push(default)
@@ -183,7 +177,6 @@
double ceil(double);
double fabs(double) __pure2;
-__BIONIC_MATH_INLINE(double fabs(double x) { return __builtin_fabs(x); })
double floor(double);
double fmod(double, double);
@@ -302,7 +295,6 @@
float ceilf(float);
float fabsf(float) __pure2;
-__BIONIC_MATH_INLINE(float fabsf(float x) { return __builtin_fabsf(x); })
float floorf(float);
float fmodf(float, float);
float roundf(float);
@@ -390,7 +382,6 @@
long double expl(long double);
long double expm1l(long double);
long double fabsl(long double) __pure2;
-__BIONIC_MATH_INLINE(long double fabsl(long double x) { return __builtin_fabsl(x); })
long double fdiml(long double, long double);
long double floorl(long double);
long double fmal(long double, long double, long double);
diff --git a/libc/include/net/if_ieee1394.h b/libc/include/net/if_ieee1394.h
index 5a61581..2f8a7c3 100644
--- a/libc/include/net/if_ieee1394.h
+++ b/libc/include/net/if_ieee1394.h
@@ -39,6 +39,8 @@
#ifndef _NET_IF_IEEE1394_H_
#define _NET_IF_IEEE1394_H_
+#include <sys/types.h>
+
/* hardware address information for arp / nd */
struct ieee1394_hwaddr {
u_int8_t iha_uid[8]; /* node unique ID */
diff --git a/libc/include/netinet/in_systm.h b/libc/include/netinet/in_systm.h
index ff53fb7..7e474ba 100644
--- a/libc/include/netinet/in_systm.h
+++ b/libc/include/netinet/in_systm.h
@@ -34,6 +34,8 @@
#ifndef _NETINET_IN_SYSTM_H_
#define _NETINET_IN_SYSTM_H_
+#include <sys/types.h>
+
/*
* Miscellaneous internetwork
* definitions for kernel.
diff --git a/libc/include/netinet/ip6.h b/libc/include/netinet/ip6.h
index aa816c2..aa89186 100644
--- a/libc/include/netinet/ip6.h
+++ b/libc/include/netinet/ip6.h
@@ -64,6 +64,10 @@
#ifndef _NETINET_IP6_H_
#define _NETINET_IP6_H_
+#include <sys/types.h>
+
+#include <linux/in6.h>
+
/*
* Definition for internet protocol version 6.
* RFC 2460
diff --git a/libc/include/netinet/tcp.h b/libc/include/netinet/tcp.h
index 5601645..e95cc09 100644
--- a/libc/include/netinet/tcp.h
+++ b/libc/include/netinet/tcp.h
@@ -29,6 +29,8 @@
#ifndef _NETINET_TCP_H
#define _NETINET_TCP_H
+#include <sys/cdefs.h>
+
#include <linux/tcp.h>
__BEGIN_DECLS
diff --git a/libc/include/nl_types.h b/libc/include/nl_types.h
new file mode 100644
index 0000000..84227bd
--- /dev/null
+++ b/libc/include/nl_types.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _NL_TYPES_H_
+#define _NL_TYPES_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#define NL_CAT_LOCALE 1
+#define NL_SETD 1
+
+typedef void* nl_catd;
+typedef int nl_item;
+
+nl_catd catopen(const char*, int);
+char* catgets(nl_catd, int, int, const char*);
+int catclose(nl_catd);
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 763bae9..5679402 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -110,15 +110,15 @@
extern int sigaction(int, const struct sigaction*, struct sigaction*);
-extern sighandler_t signal(int, sighandler_t) __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE sighandler_t signal(int, sighandler_t);
extern int siginterrupt(int, int);
-extern int sigaddset(sigset_t*, int) __INTRODUCED_IN(21);
-extern int sigdelset(sigset_t*, int) __INTRODUCED_IN(21);
-extern int sigemptyset(sigset_t*) __INTRODUCED_IN(21);
-extern int sigfillset(sigset_t*) __INTRODUCED_IN(21);
-extern int sigismember(const sigset_t*, int) __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE int sigaddset(sigset_t*, int);
+__BIONIC_LEGACY_INLINE int sigdelset(sigset_t*, int);
+__BIONIC_LEGACY_INLINE int sigemptyset(sigset_t*);
+__BIONIC_LEGACY_INLINE int sigfillset(sigset_t*);
+__BIONIC_LEGACY_INLINE int sigismember(const sigset_t*, int);
extern int sigpending(sigset_t*) __nonnull((1));
extern int sigprocmask(int, const sigset_t*, sigset_t*);
@@ -147,10 +147,8 @@
extern int sigtimedwait(const sigset_t*, siginfo_t*, const struct timespec*);
extern int sigwaitinfo(const sigset_t*, siginfo_t*);
-#if __ANDROID_API__ < 21
-#include <android/legacy_signal_inlines.h>
-#endif
-
__END_DECLS
+#include <android/legacy_signal_inlines.h>
+
#endif /* _SIGNAL_H_ */
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index 88930b1..d0fb0e8 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -76,10 +76,10 @@
extern int posix_memalign(void **memptr, size_t alignment, size_t size);
-extern double atof(const char*) __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE double atof(const char*);
extern double strtod(const char*, char**) __LIBC_ABI_PUBLIC__;
-extern float strtof(const char*, char**) __LIBC_ABI_PUBLIC__ __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE float strtof(const char*, char**) __LIBC_ABI_PUBLIC__;
extern long double strtold(const char*, char**) __LIBC_ABI_PUBLIC__;
extern long double strtold_l(const char *, char **, locale_t) __LIBC_ABI_PUBLIC__;
@@ -90,9 +90,9 @@
extern long atol(const char*) __purefunc;
extern long long atoll(const char*) __purefunc;
-extern int abs(int) __pure2 __INTRODUCED_IN(21);
-extern long labs(long) __pure2 __INTRODUCED_IN(21);
-extern long long llabs(long long) __pure2 __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE int abs(int) __pure2;
+__BIONIC_LEGACY_INLINE long labs(long) __pure2;
+__BIONIC_LEGACY_INLINE long long llabs(long long) __pure2;
extern char * realpath(const char *path, char *resolved);
extern int system(const char *string);
@@ -109,9 +109,9 @@
#define RAND_MAX 0x7fffffff
-int rand(void) __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE int rand(void);
int rand_r(unsigned int*);
-void srand(unsigned int) __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE void srand(unsigned int);
double drand48(void);
double erand48(unsigned short[3]);
@@ -124,12 +124,12 @@
void srand48(long);
char* initstate(unsigned int, char*, size_t);
-long random(void) __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE long random(void);
char* setstate(char*);
-void srandom(unsigned int) __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE void srandom(unsigned int);
int getpt(void);
-int grantpt(int) __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE int grantpt(int);
int posix_openpt(int);
char* ptsname(int);
int ptsname_r(int, char*, size_t);
@@ -174,10 +174,6 @@
extern size_t __ctype_get_mb_cur_max(void);
#define MB_CUR_MAX __ctype_get_mb_cur_max()
-#if __ANDROID_API__ < 21
-#include <android/legacy_stdlib_inlines.h>
-#endif
-
#if defined(__BIONIC_FORTIFY)
extern char* __realpath_real(const char*, char*) __RENAME(realpath);
@@ -201,4 +197,6 @@
__END_DECLS
+#include <android/legacy_stdlib_inlines.h>
+
#endif /* _STDLIB_H */
diff --git a/libc/include/string.h b/libc/include/string.h
index 32d4a18..dada52b 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -33,6 +33,8 @@
#include <stddef.h>
#include <xlocale.h>
+#include <bits/strcasecmp.h>
+
__BEGIN_DECLS
#if defined(__USE_BSD)
@@ -72,11 +74,6 @@
extern char* strcpy(char* __restrict, const char* __restrict);
extern char* strcat(char* __restrict, const char* __restrict);
-int strcasecmp(const char*, const char*) __purefunc;
-int strcasecmp_l(const char*, const char*, locale_t) __purefunc;
-int strncasecmp(const char*, const char*, size_t) __purefunc;
-int strncasecmp_l(const char*, const char*, size_t, locale_t) __purefunc;
-
extern char* strdup(const char *);
extern char* strstr(const char *, const char *) __purefunc;
diff --git a/libc/include/strings.h b/libc/include/strings.h
index 1253006..1200e77 100644
--- a/libc/include/strings.h
+++ b/libc/include/strings.h
@@ -43,6 +43,8 @@
#include <sys/cdefs.h>
#include <xlocale.h>
+#include <bits/strcasecmp.h>
+
__BEGIN_DECLS
#if defined(__BIONIC_FORTIFY)
#define bcopy(b1, b2, len) (void)(__builtin___memmove_chk((b2), (b1), (len), __bos0(b2)))
@@ -54,11 +56,6 @@
int ffs(int);
-int strcasecmp(const char*, const char*) __purefunc;
-int strcasecmp_l(const char*, const char*, locale_t) __purefunc;
-int strncasecmp(const char*, const char*, size_t) __purefunc;
-int strncasecmp_l(const char*, const char*, size_t, locale_t) __purefunc;
-
__END_DECLS
#endif /* !defined(_STRINGS_H_) */
diff --git a/libc/include/sys/atomics.h b/libc/include/sys/atomics.h
index 38ab366..b9b2ba3 100644
--- a/libc/include/sys/atomics.h
+++ b/libc/include/sys/atomics.h
@@ -38,8 +38,6 @@
* sys/atomics.h header was removed, so we'll just add these somewhere we can be
* sure they will be included.
*/
-#if __ANDROID_API__ < 21
#include <android/legacy_sys_atomics_inlines.h>
-#endif
#endif /* _SYS_ATOMICS_H_ */
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index f51942b..2bd058e 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -443,6 +443,12 @@
/* 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)
+#if __ANDROID_API__ < 21
+#define __BIONIC_LEGACY_INLINE static __inline
+#else
+#define __BIONIC_LEGACY_INLINE extern
+#endif
+
#ifdef __clang__
#define __AVAILABILITY(...) __attribute__((availability(android,__VA_ARGS__)))
#define __INTRODUCED_IN(api_level) __AVAILABILITY(introduced=api_level)
diff --git a/libc/include/sys/ioctl.h b/libc/include/sys/ioctl.h
index a1014dc..ed261f2 100644
--- a/libc/include/sys/ioctl.h
+++ b/libc/include/sys/ioctl.h
@@ -40,10 +40,6 @@
#include <sys/ioctl_compat.h>
#include <linux/tty.h>
-__BEGIN_DECLS
-
-extern int ioctl(int, int, ...);
-
-__END_DECLS
+#include <bits/ioctl.h>
#endif /* _SYS_IOCTL_H_ */
diff --git a/libc/include/sys/mman.h b/libc/include/sys/mman.h
index a19ceb5..170300a 100644
--- a/libc/include/sys/mman.h
+++ b/libc/include/sys/mman.h
@@ -65,13 +65,10 @@
extern int munlockall(void);
extern int mlock(const void*, size_t);
extern int munlock(const void*, size_t);
-extern int madvise(void*, size_t, int);
-
-extern int mlock(const void*, size_t);
-extern int munlock(const void*, size_t);
extern int mincore(void*, size_t, unsigned char*);
+extern int madvise(void*, size_t, int);
extern int posix_madvise(void*, size_t, int);
__END_DECLS
diff --git a/libc/include/sys/quota.h b/libc/include/sys/quota.h
new file mode 100644
index 0000000..f4f6447
--- /dev/null
+++ b/libc/include/sys/quota.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SYS_QUOTA_H_
+#define _SYS_QUOTA_H_
+
+#include <sys/cdefs.h>
+
+// The uapi header uses different names from userspace, oddly.
+#define if_dqblk dqblk
+#define if_dqinfo dqinfo
+#include <linux/quota.h>
+#undef if_dqblk
+#undef if_dqinfo
+
+__BEGIN_DECLS
+
+int quotactl(int, const char*, int, char*);
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index 86668f6..ae85f62 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -177,7 +177,7 @@
}
#endif /* defined(__BIONIC_FORTIFY) */
-extern int mkfifo(const char*, mode_t) __INTRODUCED_IN(21);
+__BIONIC_LEGACY_INLINE int mkfifo(const char*, mode_t);
extern int mkfifoat(int, const char*, mode_t);
extern int fchmodat(int, const char*, mode_t, int);
@@ -189,10 +189,8 @@
extern int utimensat(int fd, const char *path, const struct timespec times[2], int flags);
extern int futimens(int fd, const struct timespec times[2]);
-#if __ANDROID_API__ < 21
-#include <android/legacy_sys_stat_inlines.h>
-#endif
-
__END_DECLS
+#include <android/legacy_sys_stat_inlines.h>
+
#endif /* _SYS_STAT_H_ */
diff --git a/libc/include/sys/sysconf.h b/libc/include/sys/sysconf.h
index ca32132..c9895f2 100644
--- a/libc/include/sys/sysconf.h
+++ b/libc/include/sys/sysconf.h
@@ -25,171 +25,9 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#ifndef _SYS_SYSCONF_H_
-#define _SYS_SYSCONF_H_
-#include <sys/cdefs.h>
+// This file used to contain the declarations of sysconf and its associated constants.
+// No standard mentions a <sys/sysconf.h>, but there are enough users in vendor (and potential ones
+// in the NDK) to warrant not breaking source compatibility.
-__BEGIN_DECLS
-
-/* as listed by Posix sysconf() description */
-/* most of these will return -1 and ENOSYS */
-
-#define _SC_ARG_MAX 0x0000
-#define _SC_BC_BASE_MAX 0x0001
-#define _SC_BC_DIM_MAX 0x0002
-#define _SC_BC_SCALE_MAX 0x0003
-#define _SC_BC_STRING_MAX 0x0004
-#define _SC_CHILD_MAX 0x0005
-#define _SC_CLK_TCK 0x0006
-#define _SC_COLL_WEIGHTS_MAX 0x0007
-#define _SC_EXPR_NEST_MAX 0x0008
-#define _SC_LINE_MAX 0x0009
-#define _SC_NGROUPS_MAX 0x000a
-#define _SC_OPEN_MAX 0x000b
-#define _SC_PASS_MAX 0x000c
-#define _SC_2_C_BIND 0x000d
-#define _SC_2_C_DEV 0x000e
-#define _SC_2_C_VERSION 0x000f /* Obsolescent in POSIX.1-2008, TODO: remove it. */
-#define _SC_2_CHAR_TERM 0x0010
-#define _SC_2_FORT_DEV 0x0011
-#define _SC_2_FORT_RUN 0x0012
-#define _SC_2_LOCALEDEF 0x0013
-#define _SC_2_SW_DEV 0x0014
-#define _SC_2_UPE 0x0015
-#define _SC_2_VERSION 0x0016
-#define _SC_JOB_CONTROL 0x0017
-#define _SC_SAVED_IDS 0x0018
-#define _SC_VERSION 0x0019
-#define _SC_RE_DUP_MAX 0x001a
-#define _SC_STREAM_MAX 0x001b
-#define _SC_TZNAME_MAX 0x001c
-#define _SC_XOPEN_CRYPT 0x001d
-#define _SC_XOPEN_ENH_I18N 0x001e
-#define _SC_XOPEN_SHM 0x001f
-#define _SC_XOPEN_VERSION 0x0020
-#define _SC_XOPEN_XCU_VERSION 0x0021 /* Obsolescent in POSIX.1-2008, TODO: remove it. */
-#define _SC_XOPEN_REALTIME 0x0022
-#define _SC_XOPEN_REALTIME_THREADS 0x0023
-#define _SC_XOPEN_LEGACY 0x0024
-#define _SC_ATEXIT_MAX 0x0025
-#define _SC_IOV_MAX 0x0026
-#define _SC_PAGESIZE 0x0027
-#define _SC_PAGE_SIZE 0x0028
-#define _SC_XOPEN_UNIX 0x0029
-#define _SC_XBS5_ILP32_OFF32 0x002a /* Obsolescent in POSIX.1-2008, TODO: remove it. */
-#define _SC_XBS5_ILP32_OFFBIG 0x002b /* Obsolescent in POSIX.1-2008, TODO: remove it. */
-#define _SC_XBS5_LP64_OFF64 0x002c /* Obsolescent in POSIX.1-2008, TODO: remove it. */
-#define _SC_XBS5_LPBIG_OFFBIG 0x002d /* Obsolescent in POSIX.1-2008, TODO: remove it. */
-#define _SC_AIO_LISTIO_MAX 0x002e
-#define _SC_AIO_MAX 0x002f
-#define _SC_AIO_PRIO_DELTA_MAX 0x0030
-#define _SC_DELAYTIMER_MAX 0x0031
-#define _SC_MQ_OPEN_MAX 0x0032
-#define _SC_MQ_PRIO_MAX 0x0033
-#define _SC_RTSIG_MAX 0x0034
-#define _SC_SEM_NSEMS_MAX 0x0035
-#define _SC_SEM_VALUE_MAX 0x0036
-#define _SC_SIGQUEUE_MAX 0x0037
-#define _SC_TIMER_MAX 0x0038
-#define _SC_ASYNCHRONOUS_IO 0x0039
-#define _SC_FSYNC 0x003a
-#define _SC_MAPPED_FILES 0x003b
-#define _SC_MEMLOCK 0x003c
-#define _SC_MEMLOCK_RANGE 0x003d
-#define _SC_MEMORY_PROTECTION 0x003e
-#define _SC_MESSAGE_PASSING 0x003f
-#define _SC_PRIORITIZED_IO 0x0040
-#define _SC_PRIORITY_SCHEDULING 0x0041
-#define _SC_REALTIME_SIGNALS 0x0042
-#define _SC_SEMAPHORES 0x0043
-#define _SC_SHARED_MEMORY_OBJECTS 0x0044
-#define _SC_SYNCHRONIZED_IO 0x0045
-#define _SC_TIMERS 0x0046
-#define _SC_GETGR_R_SIZE_MAX 0x0047
-#define _SC_GETPW_R_SIZE_MAX 0x0048
-#define _SC_LOGIN_NAME_MAX 0x0049
-#define _SC_THREAD_DESTRUCTOR_ITERATIONS 0x004a
-#define _SC_THREAD_KEYS_MAX 0x004b
-#define _SC_THREAD_STACK_MIN 0x004c
-#define _SC_THREAD_THREADS_MAX 0x004d
-#define _SC_TTY_NAME_MAX 0x004e
-
-#define _SC_THREADS 0x004f
-#define _SC_THREAD_ATTR_STACKADDR 0x0050
-#define _SC_THREAD_ATTR_STACKSIZE 0x0051
-#define _SC_THREAD_PRIORITY_SCHEDULING 0x0052
-#define _SC_THREAD_PRIO_INHERIT 0x0053
-#define _SC_THREAD_PRIO_PROTECT 0x0054
-#define _SC_THREAD_SAFE_FUNCTIONS 0x0055
-
-#define _SC_NPROCESSORS_CONF 0x0060
-#define _SC_NPROCESSORS_ONLN 0x0061
-#define _SC_PHYS_PAGES 0x0062
-#define _SC_AVPHYS_PAGES 0x0063
-#define _SC_MONOTONIC_CLOCK 0x0064
-
-#define _SC_2_PBS 0x0065
-#define _SC_2_PBS_ACCOUNTING 0x0066
-#define _SC_2_PBS_CHECKPOINT 0x0067
-#define _SC_2_PBS_LOCATE 0x0068
-#define _SC_2_PBS_MESSAGE 0x0069
-#define _SC_2_PBS_TRACK 0x006a
-#define _SC_ADVISORY_INFO 0x006b
-#define _SC_BARRIERS 0x006c
-#define _SC_CLOCK_SELECTION 0x006d
-#define _SC_CPUTIME 0x006e
-#define _SC_HOST_NAME_MAX 0x006f
-#define _SC_IPV6 0x0070
-#define _SC_RAW_SOCKETS 0x0071
-#define _SC_READER_WRITER_LOCKS 0x0072
-#define _SC_REGEXP 0x0073
-#define _SC_SHELL 0x0074
-#define _SC_SPAWN 0x0075
-#define _SC_SPIN_LOCKS 0x0076
-#define _SC_SPORADIC_SERVER 0x0077
-#define _SC_SS_REPL_MAX 0x0078
-#define _SC_SYMLOOP_MAX 0x0079
-#define _SC_THREAD_CPUTIME 0x007a
-#define _SC_THREAD_PROCESS_SHARED 0x007b
-#define _SC_THREAD_ROBUST_PRIO_INHERIT 0x007c
-#define _SC_THREAD_ROBUST_PRIO_PROTECT 0x007d
-#define _SC_THREAD_SPORADIC_SERVER 0x007e
-#define _SC_TIMEOUTS 0x007f
-#define _SC_TRACE 0x0080
-#define _SC_TRACE_EVENT_FILTER 0x0081
-#define _SC_TRACE_EVENT_NAME_MAX 0x0082
-#define _SC_TRACE_INHERIT 0x0083
-#define _SC_TRACE_LOG 0x0084
-#define _SC_TRACE_NAME_MAX 0x0085
-#define _SC_TRACE_SYS_MAX 0x0086
-#define _SC_TRACE_USER_EVENT_MAX 0x0087
-#define _SC_TYPED_MEMORY_OBJECTS 0x0088
-#define _SC_V7_ILP32_OFF32 0x0089
-#define _SC_V7_ILP32_OFFBIG 0x008a
-#define _SC_V7_LP64_OFF64 0x008b
-#define _SC_V7_LPBIG_OFFBIG 0x008c
-#define _SC_XOPEN_STREAMS 0x008d
-#define _SC_XOPEN_UUCP 0x008e
-
-#define _SC_LEVEL1_ICACHE_SIZE 0x008f
-#define _SC_LEVEL1_ICACHE_ASSOC 0x0090
-#define _SC_LEVEL1_ICACHE_LINESIZE 0x0091
-#define _SC_LEVEL1_DCACHE_SIZE 0x0092
-#define _SC_LEVEL1_DCACHE_ASSOC 0x0093
-#define _SC_LEVEL1_DCACHE_LINESIZE 0x0094
-#define _SC_LEVEL2_CACHE_SIZE 0x0095
-#define _SC_LEVEL2_CACHE_ASSOC 0x0096
-#define _SC_LEVEL2_CACHE_LINESIZE 0x0097
-#define _SC_LEVEL3_CACHE_SIZE 0x0098
-#define _SC_LEVEL3_CACHE_ASSOC 0x0099
-#define _SC_LEVEL3_CACHE_LINESIZE 0x009a
-#define _SC_LEVEL4_CACHE_SIZE 0x009b
-#define _SC_LEVEL4_CACHE_ASSOC 0x009c
-#define _SC_LEVEL4_CACHE_LINESIZE 0x009d
-
-long sysconf(int);
-
-__END_DECLS
-
-#endif /* _SYS_SYSCONF_H_ */
+#include <bits/sysconf.h>
diff --git a/libc/include/termios.h b/libc/include/termios.h
index 683fde2..e604747 100644
--- a/libc/include/termios.h
+++ b/libc/include/termios.h
@@ -35,24 +35,22 @@
__BEGIN_DECLS
-#if __ANDROID_API__ >= 21
-speed_t cfgetispeed(const struct termios*);
-speed_t cfgetospeed(const struct termios*);
-void cfmakeraw(struct termios*);
-int cfsetispeed(struct termios*, speed_t);
-int cfsetospeed(struct termios*, speed_t);
-int cfsetspeed(struct termios*, speed_t);
-int tcdrain(int);
-int tcflow(int, int);
-int tcflush(int, int);
-int tcgetattr(int, struct termios*);
-pid_t tcgetsid(int);
-int tcsendbreak(int, int);
-int tcsetattr(int, int, const struct termios*);
-#else
-#include <android/legacy_termios_inlines.h>
-#endif
+__BIONIC_LEGACY_INLINE speed_t cfgetispeed(const struct termios*);
+__BIONIC_LEGACY_INLINE speed_t cfgetospeed(const struct termios*);
+__BIONIC_LEGACY_INLINE void cfmakeraw(struct termios*);
+__BIONIC_LEGACY_INLINE int cfsetispeed(struct termios*, speed_t);
+__BIONIC_LEGACY_INLINE int cfsetospeed(struct termios*, speed_t);
+__BIONIC_LEGACY_INLINE int cfsetspeed(struct termios*, speed_t);
+__BIONIC_LEGACY_INLINE int tcdrain(int);
+__BIONIC_LEGACY_INLINE int tcflow(int, int);
+__BIONIC_LEGACY_INLINE int tcflush(int, int);
+__BIONIC_LEGACY_INLINE int tcgetattr(int, struct termios*);
+__BIONIC_LEGACY_INLINE pid_t tcgetsid(int);
+__BIONIC_LEGACY_INLINE int tcsendbreak(int, int);
+__BIONIC_LEGACY_INLINE int tcsetattr(int, int, const struct termios*);
__END_DECLS
+#include <android/legacy_termios_inlines.h>
+
#endif /* _TERMIOS_H_ */
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 2d62c1f..ea6c8a1 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -33,10 +33,13 @@
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/select.h>
-#include <sys/sysconf.h>
+#include <bits/fcntl.h>
+#include <bits/getopt.h>
+#include <bits/ioctl.h>
#include <bits/lockf.h>
#include <bits/posix_limits.h>
+#include <bits/sysconf.h>
__BEGIN_DECLS
@@ -161,8 +164,6 @@
extern int dup(int __oldfd);
extern int dup2(int __oldfd, int __newfd);
extern int dup3(int __oldfd, int __newfd, int __flags) __INTRODUCED_IN(21);
-extern int fcntl(int __fd, int __cmd, ...);
-extern int ioctl(int __fd, int __request, ...);
extern int fsync(int __fd);
extern int fdatasync(int __fd) __INTRODUCED_IN(9);
@@ -207,18 +208,12 @@
extern int brk(void* __addr);
extern void* sbrk(ptrdiff_t __increment);
-extern int getopt(int __argc, char* const* __argv, const char* __argstring);
-extern char* optarg;
-extern int optind, opterr, optopt;
-
extern int isatty(int __fd);
extern char* ttyname(int __fd);
extern int ttyname_r(int __fd, char* __buf, size_t __buflen) __INTRODUCED_IN(8);
extern int acct(const char* __filepath);
-long sysconf(int __name);
-
#if __ANDROID_API__ >= 21
int getpagesize(void);
#else
diff --git a/libc/include/wchar.h b/libc/include/wchar.h
index 0a94cee..fe068be 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -97,7 +97,6 @@
extern size_t mbrtowc(wchar_t *, const char *, size_t, mbstate_t *);
extern size_t mbsrtowcs(wchar_t*, const char**, size_t, mbstate_t*);
extern size_t mbsnrtowcs(wchar_t*, const char**, size_t, size_t, mbstate_t*);
-extern size_t mbstowcs(wchar_t *, const char *, size_t);
extern wint_t putwc(wchar_t, FILE *);
extern wint_t putwchar(wchar_t);
extern int swprintf(wchar_t *, size_t, const wchar_t *, ...);
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index 2d286af..541dbb2 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1273,10 +1273,14 @@
LIBC_O {
global:
+ catclose;
+ catgets;
+ catopen;
getdomainname;
getsubopt;
hasmntopt;
pthread_getname_np;
+ quotactl;
setdomainname;
sighold;
sigignore;
@@ -1430,7 +1434,7 @@
__swrite; # arm x86 mips
__swsetup; # arm x86 mips
__truncdfsf2; # arm
- __udivdi3; # arm mips
+ __udivdi3; # arm x86 mips
__udivsi3; # arm
__unorddf2; # arm
__unordsf2; # arm
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 40f645c..1784b95 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1273,10 +1273,14 @@
LIBC_O {
global:
+ catclose;
+ catgets;
+ catopen;
getdomainname;
getsubopt;
hasmntopt;
pthread_getname_np;
+ quotactl;
setdomainname;
sighold;
sigignore;
@@ -1441,7 +1445,7 @@
__swrite; # arm x86 mips
__swsetup; # arm x86 mips
__truncdfsf2; # arm
- __udivdi3; # arm mips
+ __udivdi3; # arm x86 mips
__udivsi3; # arm
__unorddf2; # arm
__unordsf2; # arm
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 61bff70..7daa557 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1195,10 +1195,14 @@
LIBC_O {
global:
+ catclose;
+ catgets;
+ catopen;
getdomainname;
getsubopt;
hasmntopt;
pthread_getname_np;
+ quotactl;
setdomainname;
sighold;
sigignore;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index d293264..f51c5d3 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -207,7 +207,6 @@
__timer_getoverrun; # arm x86 mips
__timer_gettime; # arm x86 mips
__timer_settime; # arm x86 mips
- __udivdi3; # x86
__umask_chk;
__vsnprintf_chk;
__vsprintf_chk;
@@ -1299,10 +1298,14 @@
LIBC_O {
global:
+ catclose;
+ catgets;
+ catopen;
getdomainname;
getsubopt;
hasmntopt;
pthread_getname_np;
+ quotactl;
setdomainname;
sighold;
sigignore;
@@ -1467,7 +1470,7 @@
__swrite; # arm x86 mips
__swsetup; # arm x86 mips
__truncdfsf2; # arm
- __udivdi3; # arm mips
+ __udivdi3; # arm x86 mips
__udivsi3; # arm
__umoddi3; # x86 mips
__unorddf2; # arm
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index 5c10069..953fc29 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1257,10 +1257,14 @@
LIBC_O {
global:
+ catclose;
+ catgets;
+ catopen;
getdomainname;
getsubopt;
hasmntopt;
pthread_getname_np;
+ quotactl;
setdomainname;
sighold;
sigignore;
@@ -1290,7 +1294,7 @@
__swbuf; # arm x86 mips
__swrite; # arm x86 mips
__swsetup; # arm x86 mips
- __udivdi3; # arm mips
+ __udivdi3; # arm x86 mips
__umoddi3; # x86 mips
_fwalk; # arm x86 mips
android_getaddrinfofornet;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index baee8fb..90db79d 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1257,10 +1257,14 @@
LIBC_O {
global:
+ catclose;
+ catgets;
+ catopen;
getdomainname;
getsubopt;
hasmntopt;
pthread_getname_np;
+ quotactl;
setdomainname;
sighold;
sigignore;
@@ -1301,7 +1305,7 @@
__swbuf; # arm x86 mips
__swrite; # arm x86 mips
__swsetup; # arm x86 mips
- __udivdi3; # arm mips
+ __udivdi3; # arm x86 mips
__umoddi3; # x86 mips
__wait4; # arm x86 mips nobrillo
_fwalk; # arm x86 mips
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 61bff70..7daa557 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1195,10 +1195,14 @@
LIBC_O {
global:
+ catclose;
+ catgets;
+ catopen;
getdomainname;
getsubopt;
hasmntopt;
pthread_getname_np;
+ quotactl;
setdomainname;
sighold;
sigignore;
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index 587cf74..9f6cc52 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -203,7 +203,6 @@
__timer_getoverrun; # arm x86 mips
__timer_gettime; # arm x86 mips
__timer_settime; # arm x86 mips
- __udivdi3; # x86
__umask_chk;
__vsnprintf_chk;
__vsprintf_chk;
@@ -1256,10 +1255,14 @@
LIBC_O {
global:
+ catclose;
+ catgets;
+ catopen;
getdomainname;
getsubopt;
hasmntopt;
pthread_getname_np;
+ quotactl;
setdomainname;
sighold;
sigignore;
@@ -1290,6 +1293,7 @@
__swbuf; # arm x86 mips
__swrite; # arm x86 mips
__swsetup; # arm x86 mips
+ __udivdi3; # arm x86 mips
__umoddi3; # x86 mips
_fwalk; # arm x86 mips
android_getaddrinfofornet;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 9a38ee9..4443731 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -203,7 +203,6 @@
__timer_getoverrun; # arm x86 mips
__timer_gettime; # arm x86 mips
__timer_settime; # arm x86 mips
- __udivdi3; # x86
__umask_chk;
__vsnprintf_chk;
__vsprintf_chk;
@@ -1256,10 +1255,14 @@
LIBC_O {
global:
+ catclose;
+ catgets;
+ catopen;
getdomainname;
getsubopt;
hasmntopt;
pthread_getname_np;
+ quotactl;
setdomainname;
sighold;
sigignore;
@@ -1301,6 +1304,7 @@
__swbuf; # arm x86 mips
__swrite; # arm x86 mips
__swsetup; # arm x86 mips
+ __udivdi3; # arm x86 mips
__umoddi3; # x86 mips
__wait4; # arm x86 mips nobrillo
_fwalk; # arm x86 mips
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 61bff70..7daa557 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1195,10 +1195,14 @@
LIBC_O {
global:
+ catclose;
+ catgets;
+ catopen;
getdomainname;
getsubopt;
hasmntopt;
pthread_getname_np;
+ quotactl;
setdomainname;
sighold;
sigignore;
diff --git a/libc/malloc_debug/BacktraceData.cpp b/libc/malloc_debug/BacktraceData.cpp
index 400e282..3d46bf0 100644
--- a/libc/malloc_debug/BacktraceData.cpp
+++ b/libc/malloc_debug/BacktraceData.cpp
@@ -41,27 +41,24 @@
#include "debug_log.h"
#include "malloc_debug.h"
-BacktraceData::BacktraceData(const Config& config, size_t* offset) {
+static void EnableToggle(int, siginfo_t*, void*) {
+ if (g_debug->backtrace->enabled()) {
+ g_debug->backtrace->set_enabled(false);
+ } else {
+ g_debug->backtrace->set_enabled(true);
+ }
+}
+
+BacktraceData::BacktraceData(DebugData* debug_data, const Config& config, size_t* offset)
+ : OptionData(debug_data) {
size_t hdr_len = sizeof(BacktraceHeader) + sizeof(uintptr_t) * config.backtrace_frames;
alloc_offset_ = *offset;
*offset += BIONIC_ALIGN(hdr_len, MINIMUM_ALIGNMENT_BYTES);
}
-static BacktraceData* g_backtrace_data = nullptr;
-
-static void EnableToggle(int, siginfo_t*, void*) {
- if (g_backtrace_data->enabled()) {
- g_backtrace_data->set_enabled(false);
- } else {
- g_backtrace_data->set_enabled(true);
- }
-}
-
bool BacktraceData::Initialize(const Config& config) {
enabled_ = config.backtrace_enabled;
if (config.backtrace_enable_on_signal) {
- g_backtrace_data = this;
-
struct sigaction enable_act;
memset(&enable_act, 0, sizeof(enable_act));
diff --git a/libc/malloc_debug/BacktraceData.h b/libc/malloc_debug/BacktraceData.h
index 842e372..dbc3989 100644
--- a/libc/malloc_debug/BacktraceData.h
+++ b/libc/malloc_debug/BacktraceData.h
@@ -33,12 +33,14 @@
#include <private/bionic_macros.h>
+#include "OptionData.h"
+
// Forward declarations.
struct Config;
-class BacktraceData {
+class BacktraceData : public OptionData {
public:
- BacktraceData(const Config& config, size_t* offset);
+ BacktraceData(DebugData* debug_data, const Config& config, size_t* offset);
virtual ~BacktraceData() = default;
bool Initialize(const Config& config);
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index ded618c..cc60086 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -273,7 +273,7 @@
fill_free_value = DEFAULT_FILL_FREE_VALUE;
front_guard_value = DEFAULT_FRONT_GUARD_VALUE;
rear_guard_value = DEFAULT_REAR_GUARD_VALUE;
- backtrace_signal = SIGRTMIN + 10;
+ backtrace_signal = SIGRTMAX - 19;
free_track_backtrace_num_frames = 16;
// Parse the options are of the format:
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index cb1de5a..3ee93b2 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -49,8 +49,8 @@
constexpr size_t MINIMUM_ALIGNMENT_BYTES = 8;
#endif
-// If only one or more of these options is set, then no special header is needed.
-constexpr uint64_t NO_HEADER_OPTIONS = FILL_ON_ALLOC | FILL_ON_FREE | EXPAND_ALLOC;
+// If one or more of these options is set, then a special header is needed.
+constexpr uint64_t HEADER_OPTIONS = FRONT_GUARD | REAR_GUARD | BACKTRACE | FREE_TRACK | LEAK_TRACK;
struct Config {
bool SetFromProperties();
diff --git a/libc/malloc_debug/DebugData.cpp b/libc/malloc_debug/DebugData.cpp
index 0447566..58cbbcb 100644
--- a/libc/malloc_debug/DebugData.cpp
+++ b/libc/malloc_debug/DebugData.cpp
@@ -43,37 +43,37 @@
}
// Check to see if the options that require a header are enabled.
- if ((config_.options & ~(NO_HEADER_OPTIONS)) != 0) {
+ if (config_.options & HEADER_OPTIONS) {
need_header_ = true;
// Initialize all of the static header offsets.
pointer_offset_ = BIONIC_ALIGN(sizeof(Header), MINIMUM_ALIGNMENT_BYTES);
if (config_.options & BACKTRACE) {
- backtrace.reset(new BacktraceData(config_, &pointer_offset_));
+ backtrace.reset(new BacktraceData(this, config_, &pointer_offset_));
if (!backtrace->Initialize(config_)) {
return false;
}
}
if (config_.options & FRONT_GUARD) {
- front_guard.reset(new FrontGuardData(config_, &pointer_offset_));
+ front_guard.reset(new FrontGuardData(this, config_, &pointer_offset_));
}
extra_bytes_ = pointer_offset_;
// Initialize all of the non-header data.
if (config_.options & REAR_GUARD) {
- rear_guard.reset(new RearGuardData(config_));
+ rear_guard.reset(new RearGuardData(this, config_));
extra_bytes_ += config_.rear_guard_bytes;
}
if (config_.options & FREE_TRACK) {
- free_track.reset(new FreeTrackData(config_));
+ free_track.reset(new FreeTrackData(this, config_));
}
if (config_.options & TRACK_ALLOCS) {
- track.reset(new TrackData());
+ track.reset(new TrackData(this));
}
}
diff --git a/libc/malloc_debug/DebugData.h b/libc/malloc_debug/DebugData.h
index 4600b33..7e55512 100644
--- a/libc/malloc_debug/DebugData.h
+++ b/libc/malloc_debug/DebugData.h
@@ -103,4 +103,6 @@
DISALLOW_COPY_AND_ASSIGN(DebugData);
};
+extern DebugData* g_debug;
+
#endif // MALLOC_DEBUG_DEBUGDATA_H
diff --git a/libc/malloc_debug/FreeTrackData.cpp b/libc/malloc_debug/FreeTrackData.cpp
index ed41981..8e6502e 100644
--- a/libc/malloc_debug/FreeTrackData.cpp
+++ b/libc/malloc_debug/FreeTrackData.cpp
@@ -36,22 +36,19 @@
#include "FreeTrackData.h"
#include "malloc_debug.h"
-FreeTrackData::FreeTrackData(const Config& config)
- : backtrace_num_frames_(config.free_track_backtrace_num_frames) {
+FreeTrackData::FreeTrackData(DebugData* debug, const Config& config)
+ : OptionData(debug), backtrace_num_frames_(config.free_track_backtrace_num_frames) {
cmp_mem_.resize(4096);
memset(cmp_mem_.data(), config.fill_free_value, cmp_mem_.size());
}
-void FreeTrackData::LogFreeError(DebugData& debug, const Header* header,
- const uint8_t* pointer) {
- ScopedDisableDebugCalls disable;
-
+void FreeTrackData::LogFreeError(const Header* header, const uint8_t* pointer) {
error_log(LOG_DIVIDER);
error_log("+++ ALLOCATION %p USED AFTER FREE", pointer);
- uint8_t fill_free_value = debug.config().fill_free_value;
+ uint8_t fill_free_value = debug_->config().fill_free_value;
for (size_t i = 0; i < header->usable_size; i++) {
if (pointer[i] != fill_free_value) {
- error_log(" pointer[%zu] = 0x%02x (expected 0x%02x)", i, pointer[i], fill_free_value);
+ error_log(" allocation[%zu] = 0x%02x (expected 0x%02x)", i, pointer[i], fill_free_value);
}
}
auto back_iter = backtraces_.find(header);
@@ -63,10 +60,8 @@
error_log(LOG_DIVIDER);
}
-void FreeTrackData::VerifyAndFree(DebugData& debug, const Header* header,
- const void* pointer) {
- ScopedDisableDebugCalls disable;
-
+void FreeTrackData::VerifyAndFree(const Header* header) {
+ const void* pointer = debug_->GetPointer(header);
if (header->tag != DEBUG_FREE_TAG) {
error_log(LOG_DIVIDER);
error_log("+++ ALLOCATION %p HAS CORRUPTED HEADER TAG 0x%x AFTER FREE", pointer, header->tag);
@@ -74,11 +69,12 @@
} else {
const uint8_t* memory = reinterpret_cast<const uint8_t*>(pointer);
size_t bytes = header->usable_size;
- bytes = (bytes < debug.config().fill_on_free_bytes) ? bytes : debug.config().fill_on_free_bytes;
+ bytes = (bytes < debug_->config().fill_on_free_bytes) ? bytes
+ : debug_->config().fill_on_free_bytes;
while (bytes > 0) {
size_t bytes_to_cmp = (bytes < cmp_mem_.size()) ? bytes : cmp_mem_.size();
if (memcmp(memory, cmp_mem_.data(), bytes_to_cmp) != 0) {
- LogFreeError(debug, header, reinterpret_cast<const uint8_t*>(pointer));
+ LogFreeError(header, reinterpret_cast<const uint8_t*>(pointer));
break;
}
bytes -= bytes_to_cmp;
@@ -94,14 +90,11 @@
g_dispatch->free(header->orig_pointer);
}
-void FreeTrackData::Add(DebugData& debug, const Header* header) {
- // Make sure the stl calls below don't call the debug_XXX functions.
- ScopedDisableDebugCalls disable;
-
+void FreeTrackData::Add(const Header* header) {
pthread_mutex_lock(&mutex_);
- if (list_.size() == debug.config().free_track_allocations) {
+ if (list_.size() == debug_->config().free_track_allocations) {
const Header* old_header = list_.back();
- VerifyAndFree(debug, old_header, debug.GetPointer(old_header));
+ VerifyAndFree(old_header);
list_.pop_back();
}
@@ -118,19 +111,14 @@
pthread_mutex_unlock(&mutex_);
}
-void FreeTrackData::VerifyAll(DebugData& debug) {
- // Make sure the stl calls below don't call the debug_XXX functions.
- ScopedDisableDebugCalls disable;
-
+void FreeTrackData::VerifyAll() {
for (const auto& header : list_) {
- VerifyAndFree(debug, header, debug.GetPointer(header));
+ VerifyAndFree(header);
}
list_.clear();
}
void FreeTrackData::LogBacktrace(const Header* header) {
- ScopedDisableDebugCalls disable;
-
auto back_iter = backtraces_.find(header);
if (back_iter == backtraces_.end()) {
return;
diff --git a/libc/malloc_debug/FreeTrackData.h b/libc/malloc_debug/FreeTrackData.h
index 804b5a6..21f845f 100644
--- a/libc/malloc_debug/FreeTrackData.h
+++ b/libc/malloc_debug/FreeTrackData.h
@@ -38,26 +38,28 @@
#include <private/bionic_macros.h>
-// Forward declarations.
-struct Header;
-class DebugData;
-struct Config;
-struct BacktraceHeader;
+#include "OptionData.h"
-class FreeTrackData {
+// Forward declarations.
+struct BacktraceHeader;
+struct Config;
+class DebugData;
+struct Header;
+
+class FreeTrackData : public OptionData {
public:
- FreeTrackData(const Config& config);
+ FreeTrackData(DebugData* debug_data, const Config& config);
virtual ~FreeTrackData() = default;
- void Add(DebugData& debug, const Header* header);
+ void Add(const Header* header);
- void VerifyAll(DebugData& debug);
+ void VerifyAll();
void LogBacktrace(const Header* header);
private:
- void LogFreeError(DebugData& debug, const Header* header, const uint8_t* pointer);
- void VerifyAndFree(DebugData& debug, const Header* header, const void* pointer);
+ void LogFreeError(const Header* header, const uint8_t* pointer);
+ void VerifyAndFree(const Header* header);
pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
std::deque<const Header*> list_;
diff --git a/libc/malloc_debug/GuardData.cpp b/libc/malloc_debug/GuardData.cpp
index c70e8f1..e207b86 100644
--- a/libc/malloc_debug/GuardData.cpp
+++ b/libc/malloc_debug/GuardData.cpp
@@ -39,15 +39,14 @@
#include "malloc_debug.h"
#include "GuardData.h"
-GuardData::GuardData(int init_value, size_t num_bytes) {
+GuardData::GuardData(DebugData* debug_data, int init_value, size_t num_bytes)
+ : OptionData(debug_data) {
// Create a buffer for fast comparisons of the front guard.
cmp_mem_.resize(num_bytes);
memset(cmp_mem_.data(), init_value, cmp_mem_.size());
}
void GuardData::LogFailure(const Header* header, const void* pointer, const void* data) {
- ScopedDisableDebugCalls disable;
-
error_log(LOG_DIVIDER);
error_log("+++ ALLOCATION %p SIZE %zu HAS A CORRUPTED %s GUARD", pointer,
header->real_size(), GetTypeName());
@@ -58,7 +57,7 @@
const uint8_t* real = reinterpret_cast<const uint8_t*>(data);
for (size_t i = 0; i < cmp_mem_.size(); i++, pointer_idx++) {
if (real[i] != expected[i]) {
- error_log(" pointer[%d] = 0x%02x (expected 0x%02x)", pointer_idx, real[i], expected[i]);
+ error_log(" allocation[%d] = 0x%02x (expected 0x%02x)", pointer_idx, real[i], expected[i]);
}
}
@@ -70,8 +69,8 @@
error_log(LOG_DIVIDER);
}
-FrontGuardData::FrontGuardData(const Config& config, size_t* offset)
- : GuardData(config.front_guard_value, config.front_guard_bytes) {
+FrontGuardData::FrontGuardData(DebugData* debug_data, const Config& config, size_t* offset)
+ : GuardData(debug_data, config.front_guard_value, config.front_guard_bytes) {
// Create a buffer for fast comparisons of the front guard.
cmp_mem_.resize(config.front_guard_bytes);
memset(cmp_mem_.data(), config.front_guard_value, cmp_mem_.size());
@@ -80,22 +79,22 @@
*offset += config.front_guard_bytes;
}
-bool FrontGuardData::Valid(DebugData& debug, const Header* header) {
- return GuardData::Valid(debug.GetFrontGuard(header));
+bool FrontGuardData::Valid(const Header* header) {
+ return GuardData::Valid(debug_->GetFrontGuard(header));
}
-void FrontGuardData::LogFailure(DebugData& debug, const Header* header) {
- GuardData::LogFailure(header, debug.GetPointer(header), debug.GetFrontGuard(header));
+void FrontGuardData::LogFailure(const Header* header) {
+ GuardData::LogFailure(header, debug_->GetPointer(header), debug_->GetFrontGuard(header));
}
-RearGuardData::RearGuardData(const Config& config)
- : GuardData(config.rear_guard_value, config.rear_guard_bytes) {
+RearGuardData::RearGuardData(DebugData* debug_data, const Config& config)
+ : GuardData(debug_data, config.rear_guard_value, config.rear_guard_bytes) {
}
-bool RearGuardData::Valid(DebugData& debug, const Header* header) {
- return GuardData::Valid(debug.GetRearGuard(header));
+bool RearGuardData::Valid(const Header* header) {
+ return GuardData::Valid(debug_->GetRearGuard(header));
}
-void RearGuardData::LogFailure(DebugData& debug, const Header* header) {
- GuardData::LogFailure(header, debug.GetPointer(header), debug.GetRearGuard(header));
+void RearGuardData::LogFailure(const Header* header) {
+ GuardData::LogFailure(header, debug_->GetPointer(header), debug_->GetRearGuard(header));
}
diff --git a/libc/malloc_debug/GuardData.h b/libc/malloc_debug/GuardData.h
index 4de2702..bfb3949 100644
--- a/libc/malloc_debug/GuardData.h
+++ b/libc/malloc_debug/GuardData.h
@@ -36,14 +36,16 @@
#include <private/bionic_macros.h>
+#include "OptionData.h"
+
// Forward declarations.
class DebugData;
struct Header;
struct Config;
-class GuardData {
+class GuardData : public OptionData {
public:
- GuardData(int init_value, size_t num_bytes);
+ GuardData(DebugData* debug_data, int init_value, size_t num_bytes);
virtual ~GuardData() = default;
bool Valid(void* data) { return memcmp(data, cmp_mem_.data(), cmp_mem_.size()) == 0; }
@@ -60,12 +62,12 @@
class FrontGuardData : public GuardData {
public:
- FrontGuardData(const Config& config, size_t* offset);
+ FrontGuardData(DebugData* debug_data, const Config& config, size_t* offset);
virtual ~FrontGuardData() = default;
- bool Valid(DebugData& debug, const Header* header);
+ bool Valid(const Header* header);
- void LogFailure(DebugData& debug, const Header* header);
+ void LogFailure(const Header* header);
size_t offset() { return offset_; }
@@ -79,12 +81,12 @@
class RearGuardData : public GuardData {
public:
- RearGuardData(const Config& config);
+ RearGuardData(DebugData* debug_data, const Config& config);
virtual ~RearGuardData() = default;
- bool Valid(DebugData& debug, const Header* header);
+ bool Valid(const Header* header);
- void LogFailure(DebugData& debug, const Header* header);
+ void LogFailure(const Header* header);
private:
const char* GetTypeName() override { return "REAR"; }
diff --git a/libc/malloc_debug/OptionData.h b/libc/malloc_debug/OptionData.h
new file mode 100644
index 0000000..80190f5
--- /dev/null
+++ b/libc/malloc_debug/OptionData.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DEBUG_MALLOC_OPTIONDATA_H
+#define DEBUG_MALLOC_OPTIONDATA_H
+
+// Forward Declarations
+class DebugData;
+
+class OptionData {
+ public:
+ OptionData(DebugData* debug) : debug_(debug) {}
+ ~OptionData() = default;
+
+ protected:
+ DebugData* debug_;
+
+ DISALLOW_COPY_AND_ASSIGN(OptionData);
+};
+
+#endif // MALLOC_DEBUG_OPTIONDATA_H
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
new file mode 100644
index 0000000..3fc2305
--- /dev/null
+++ b/libc/malloc_debug/README.md
@@ -0,0 +1,330 @@
+Malloc Debug
+============
+
+Malloc debug is a method of debugging native memory problems. It can help
+detect memory corruption, memory leaks, and use after free issues.
+
+Currently, malloc debug requires root to enable. When it is enabled, it works
+by adding a shim layer that replaces the normal allocation calls. The replaced
+calls are:
+
+<pre>
+malloc
+free
+calloc
+realloc
+posix_memalign
+memalign
+malloc_usable_size
+</pre>
+
+On 32 bit systems, these two deprecated functions are also replaced:
+
+<pre>
+pvalloc
+valloc
+</pre>
+
+Any errors detected by the library are reported in the log.
+
+Controlling Malloc Debug Behavior
+---------------------------------
+Malloc debug is controlled by individual options. Each option can be enabled
+individually, or in a group of other options. Every single option can be
+combined with every other option.
+
+Option Descriptions
+-------------------
+### front\_guard[=SIZE\_BYTES]
+Enables a small buffer placed before the allocated data. This is an attempt
+to find memory corruption occuring to a region before the original allocation.
+On first allocation, this front guard is written with a specific pattern (0xaa).
+When the allocation is freed, the guard is checked to verify it has not been
+modified. If any part of the front guard is modified, an error will be reported
+in the log indicating what bytes changed.
+
+If the backtrace option is also enabled, then any error message will include
+the backtrace of the allocation site.
+
+If SIZE\_BYTES is present, it indicates the number of bytes in the guard.
+The default is 32 bytes, the max bytes is 16384. SIZE\_BYTES will be
+padded so that it is a multiple of 8 bytes on 32 bit systems and 16 bytes
+on 64 bit systems to make sure that the allocation returned is aligned
+properly.
+
+This option adds a special header to all allocations that contains the guard
+and information about the original allocation.
+
+Example error:
+
+<pre>
+04-10 12:00:45.621 7412 7412 E malloc_debug: +++ ALLOCATION 0x12345678 SIZE 100 HAS A CORRUPTED FRONT GUARD
+04-10 12:00:45.622 7412 7412 E malloc_debug: allocation[-32] = 0x00 (expected 0xaa)
+04-10 12:00:45.622 7412 7412 E malloc_debug: allocation[-15] = 0x02 (expected 0xaa)
+</pre>
+
+### rear\_guard[=SIZE\_BYTES]
+Enables a small buffer placed after the allocated data. This is an attempt
+to find memory corruption occuring to a region after the original allocation.
+On first allocation, this rear guard is written with a specific pattern (0xbb).
+When the allocation is freed, the guard is checked to verify it has not been
+modified. If any part of the rear guard is modified, an error will be reported
+in the log indicating what bytes changed.
+
+If SIZE\_BYTES is present, it indicates the number of bytes in the guard.
+The default is 32 bytes, the max bytes is 16384.
+
+This option adds a special header to all allocations that contains
+information about the original allocation.
+
+Example error:
+
+<pre>
+04-10 12:00:45.621 7412 7412 E malloc_debug: +++ ALLOCATION 0x12345678 SIZE 100 HAS A CORRUPTED REAR GUARD
+04-10 12:00:45.622 7412 7412 E malloc_debug: allocation[130] = 0xbf (expected 0xbb)
+04-10 12:00:45.622 7412 7412 E malloc_debug: allocation[131] = 0x00 (expected 0xbb)
+</pre>
+
+### guard[=SIZE\_BYTES]
+Enables both a front guard and a rear guard on all allocations.
+
+If SIZE\_BYTES is present, it indicates the number of bytes in both guards.
+The default is 32 bytes, the max bytes is 16384.
+
+### backtrace[=MAX\_FRAMES]
+Enable capturing the backtrace of each allocation site.
+This option will slow down allocations by an order of magnitude. If the
+system runs too slowly with this option enabled, decreasing the maximum number
+of frames captured will speed the allocations up.
+
+Note that any backtrace frames that occur within the malloc backtrace library
+itself are not recorded.
+
+If MAX\_FRAMES is present, it indicates the maximum number of frames to
+capture in a backtrace. The default is 16 frames, the maximumum value
+this can be set to is 256.
+
+This option adds a special header to all allocations that contains the
+backtrace and information about the original allocation.
+
+### backtrace\_enable\_on\_signal[=MAX\_FRAMES]
+Enable capturing the backtrace of each allocation site. If the
+backtrace capture is toggled when the process receives the signal
+SIGRTMAX - 19 (which is 45 on most Android devices). When this
+option is used alone, backtrace capture starts out disabled until the signal
+is received. If both this option and the backtrace option are set, then
+backtrace capture is enabled until the signal is received.
+
+If MAX\_FRAMES is present, it indicates the maximum number of frames to
+capture in a backtrace. The default is 16 frames, the maximumum value
+this can be set to is 256.
+
+This option adds a special header to all allocations that contains the
+backtrace and information about the original allocation.
+
+### fill\_on\_alloc[=MAX\_FILLED\_BYTES]
+Any allocation routine, other than calloc, will result in the allocation being
+filled with the value 0xeb. When doing a realloc to a larger size, the bytes
+above the original usable size will be set to 0xeb.
+
+If MAX\_FILLED\_BYTES is present, it will only fill up to the specified number
+of bytes in the allocation. The default is to fill the entire allocation.
+
+### fill\_on\_free[=MAX\_FILLED\_BYTES]
+When an allocation is freed, fill it with 0xef.
+
+If MAX\_FILLED\_BYTES is present, it will only fill up to the specified number
+of bytes in the allocation. The default is to fill the entire allocation.
+
+### fill[=MAX\_FILLED\_BYTES]
+This enables both the fill\_on\_alloc option and the fill\_on\_free option.
+
+If MAX\_FILLED\_BYTES is present, it will only fill up to the specified number
+of bytes in the allocation. The default is to fill the entire allocation.
+
+### expand\_alloc[=EXPAND\_BYTES]
+Add an extra amount to allocate for every allocation.
+
+If XX is present, it is the number of bytes to expand the allocation by.
+The default is 16 bytes, the max bytes is 16384.
+
+### free\_track[=ALLOCATION\_COUNT]
+When a pointer is freed, do not free the memory right away, but add it to
+a list of freed allocations. In addition to being added to the list, the
+entire allocation is filled with the value 0xef, and the backtrace at
+the time of the free is recorded. The backtrace recording is completely
+separate from the backtrace option, and happens automatically if this
+option is enabled. By default, a maximum of 16 frames will be recorded,
+but this value can be changed using the free\_track\_backtrace\_num\_frames
+option. It can also be completely disabled by setting the option to zero.
+See the full description of this option below.
+
+When the list is full, an allocation is removed from the list and is
+checked to make sure that none of the contents have been modified since
+being placed on the list. When the program terminates, all of the allocations
+left on the list are verified.
+
+If ALLOCATION\_COUNT is present, it indicates the total number of allocations
+in the list. The default is to record 100 freed allocations, the max
+allocations to record is 16384.
+
+This option adds a special header to all allocations that contains
+information about the original allocation.
+
+Example error:
+
+<pre>
+04-15 12:00:31.304 7412 7412 E malloc_debug: +++ ALLOCATION 0x12345678 USED AFTER FREE
+04-15 12:00:31.305 7412 7412 E malloc_debug: allocation[20] = 0xaf (expected 0xef)
+04-15 12:00:31.305 7412 7412 E malloc_debug: allocation[99] = 0x12 (expected 0xef)
+04-15 12:00:31.305 7412 7412 E malloc_debug: Backtrace at time of free:
+04-15 12:00:31.305 7412 7412 E malloc_debug: #00 pc 00029310 /system/lib/libc.so
+04-15 12:00:31.305 7412 7412 E malloc_debug: #01 pc 00021438 /system/lib/libc.so (newlocale+160)
+04-15 12:00:31.305 7412 7412 E malloc_debug: #02 pc 000a9e38 /system/lib/libc++.so
+04-15 12:00:31.305 7412 7412 E malloc_debug: #03 pc 000a28a8 /system/lib/libc++.so
+</pre>
+
+In addition, there is another type of error message that can occur if
+an allocation has a special header applied, and the header is corrupted
+before the verification occurs. This is the error message that will be found
+in the log:
+
+<pre>
++++ ALLOCATION 0x12345678 HAS CORRUPTED HEADER TAG 0x1cc7dc00 AFTER FREE
+</pre>
+
+### free\_track\_backtrace\_num\_frames[=MAX\_FRAMES]
+This option only has meaning if free\_track is set. It indicates how many
+backtrace frames to capture when an allocation is freed.
+
+If MAX\_FRAMES is present, it indicates the number of frames to capture.
+If the value is set to zero, then no backtrace will be captured when the
+allocation is freed. The default is to record 16 frames, the max number of
+frames to to record is 256.
+
+### leak\_track
+Track all live allocations. When the program terminates, all of the live
+allocations will be dumped to the log. If the backtrace option was enabled,
+then the log will include the backtrace of the leaked allocations. This
+option is not useful when enabled globally because a lot of programs do not
+free everything before the program terminates.
+
+This option adds a special header to all allocations that contains
+information about the original allocation.
+
+Example leak error found in the log:
+
+<pre>
+04-15 12:35:33.304 7412 7412 E malloc_debug: +++ APP leaked block of size 100 at 0x2be3b0b0 (leak 1 of 2)
+04-15 12:35:33.304 7412 7412 E malloc_debug: Backtrace at time of allocation:
+04-15 12:35:33.305 7412 7412 E malloc_debug: #00 pc 00029310 /system/lib/libc.so
+04-15 12:35:33.305 7412 7412 E malloc_debug: #01 pc 00021438 /system/lib/libc.so (newlocale+160)
+04-15 12:35:33.305 7412 7412 E malloc_debug: #02 pc 000a9e38 /system/lib/libc++.so
+04-15 12:35:33.305 7412 7412 E malloc_debug: #03 pc 000a28a8 /system/lib/libc++.so
+04-15 12:35:33.305 7412 7412 E malloc_debug: +++ APP leaked block of size 24 at 0x7be32380 (leak 2 of 2)
+04-15 12:35:33.305 7412 7412 E malloc_debug: Backtrace at time of allocation:
+04-15 12:35:33.305 7412 7412 E malloc_debug: #00 pc 00029310 /system/lib/libc.so
+04-15 12:35:33.305 7412 7412 E malloc_debug: #01 pc 00021438 /system/lib/libc.so (newlocale+160)
+04-15 12:35:33.305 7412 7412 E malloc_debug: #02 pc 000a9e38 /system/lib/libc++.so
+04-15 12:35:33.305 7412 7412 E malloc_debug: #03 pc 000a28a8 /system/lib/libc++.so
+</pre>
+
+Additional Errors
+-----------------
+There are a few other error messages that might appear in the log.
+
+### Use After Free
+<pre>
+04-15 12:00:31.304 7412 7412 E malloc_debug: +++ ALLOCATION 0x12345678 USED AFTER FREE (free)
+04-15 12:00:31.305 7412 7412 E malloc_debug: Backtrace of original free:
+04-15 12:00:31.305 7412 7412 E malloc_debug: #00 pc 00029310 /system/lib/libc.so
+04-15 12:00:31.305 7412 7412 E malloc_debug: #01 pc 00021438 /system/lib/libc.so (newlocale+160)
+04-15 12:00:31.305 7412 7412 E malloc_debug: #02 pc 000a9e38 /system/lib/libc++.so
+04-15 12:00:31.305 7412 7412 E malloc_debug: #03 pc 000a28a8 /system/lib/libc++.so
+04-15 12:00:31.305 7412 7412 E malloc_debug: Backtrace at time of failure:
+04-15 12:00:31.305 7412 7412 E malloc_debug: #00 pc 00029310 /system/lib/libc.so
+04-15 12:00:31.305 7412 7412 E malloc_debug: #01 pc 00021438 /system/lib/libc.so (newlocale+160)
+04-15 12:00:31.305 7412 7412 E malloc_debug: #02 pc 000a9e38 /system/lib/libc++.so
+04-15 12:00:31.305 7412 7412 E malloc_debug: #03 pc 000a28a8 /system/lib/libc++.so
+</pre>
+
+This indicates that code is attempting to free an already freed pointer. The
+name in parenthesis indicates that the application called the function
+<i>free</i> with the bad pointer.
+
+For example, this message:
+
+<pre>
+04-15 12:00:31.304 7412 7412 E malloc_debug: +++ ALLOCATION 0x12345678 USED AFTER FREE (realloc)
+</pre>
+
+Would indicate that the application called the <i>realloc</i> function
+with an already freed pointer.
+
+### Invalid Tag
+<pre>
+04-15 12:00:31.304 7412 7412 E malloc_debug: +++ ALLOCATION 0x12345678 HAS INVALID TAG 1ee7d000 (malloc_usable_size)
+04-15 12:00:31.305 7412 7412 E malloc_debug: Backtrace at time of failure:
+04-15 12:00:31.305 7412 7412 E malloc_debug: #00 pc 00029310 /system/lib/libc.so
+04-15 12:00:31.305 7412 7412 E malloc_debug: #01 pc 00021438 /system/lib/libc.so (newlocale+160)
+04-15 12:00:31.305 7412 7412 E malloc_debug: #02 pc 000a9e38 /system/lib/libc++.so
+04-15 12:00:31.305 7412 7412 E malloc_debug: #03 pc 000a28a8 /system/lib/libc++.so
+</pre>
+
+This indicates that a function (malloc\_usable\_size) was called with
+a pointer that is either not allocated memory, or that the memory of
+the pointer has been corrupted.
+
+As with the other error message, the function in parenthesis is the
+function that was called with the bad pointer.
+
+Examples
+========
+Enable backtrace tracking of all allocation for all processes:
+
+<pre>
+ adb shell stop
+ adb shell setprop libc.debug.malloc.options backtrace
+ adb shell start
+</pre>
+
+Enable backtrace tracking for a specific process (ls):
+
+<pre>
+ adb shell setprop libc.debug.malloc.options backtrace
+ adb shell setprop libc.debug.malloc.program ls
+ adb shell ls
+</pre>
+
+Enable backtrace tracking for the zygote and zygote based processes:
+
+<pre>
+ adb shell stop
+ adb shell setprop libc.debug.malloc.program app_process
+ adb shell setprop libc.debug.malloc.options backtrace
+ adb shell start
+</pre>
+
+Enable multiple options (backtrace and guards):
+
+<pre>
+ adb shell stop
+ adb shell setprop libc.debug.malloc.options "\"backtrace guards\""
+ adb shell start
+</pre>
+
+Enable malloc debug when multiple processes have the same name. This method
+can be used to enable malloc debug for only a very specific process if
+multiple processes have the same name.
+
+Note: The double quotes in the adb shell command are necessary. Otherwise,
+the setprop command will fail since the backtrace guards options will look
+like two arguments instead of one.
+
+<pre>
+ adb shell
+ # setprop libc.debug.malloc.env_enabled
+ # setprop libc.debug.malloc.options backtrace
+ # export LIBC_DEBUG_MALLOC_ENABLE 1
+ # ls
+</pre>
diff --git a/libc/malloc_debug/README_api.md b/libc/malloc_debug/README_api.md
new file mode 100644
index 0000000..cd04c32
--- /dev/null
+++ b/libc/malloc_debug/README_api.md
@@ -0,0 +1,64 @@
+Native Memory Tracking using libc Callbacks
+-------------------------------------------
+Malloc debug can be used to get information on all of the live allocations
+in a process. The libc library in Android exports two calls that can be
+used to gather this data from a process. This tracking can be enabled using
+either the backtrace option or the backtrace\_enabled\_on\_signal option.
+
+The function to gather the data:
+
+<pre>
+<b>
+extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory, size_t* backtrace_size);
+</b>
+</pre>
+
+<i>info</i> is set to a buffer allocated by the call that contains all of
+the allocation information.
+<i>overall\_size</i> is set to the total size of the buffer returned. If this
+<i>info\_size</i>
+value is zero, then there are no allocation being tracked.
+<i>total\_memory</i> is set to the sum of all allocation sizes that are live at
+the point of the function call. This does not include the memory allocated
+by the malloc debug library itself.
+<i>backtrace\_size</i> is set to the maximum number of backtrace entries
+that are present for each allocation.
+
+In order to free the buffer allocated by the function, call:
+
+<pre>
+<b>
+extern "C" void free_malloc_leak_info(uint8_t* info);
+</b>
+</pre>
+
+### Format of info Buffer
+<pre>
+size_t size_of_original_allocation
+size_t num_backtrace_frames
+uintptr_t pc1
+uintptr_t pc2
+uintptr_t pc3
+.
+.
+.
+</pre>
+
+The number of <i>uintptr\_t</i> values is determined by the value
+<i>backtrace\_size</i> as returned by the original call to
+<i>get\_malloc\_leak\_info</i>. This value is not variable, it is the same
+for all the returned data. The value
+<i>num\_backtrace\_frames</i> contains the real number of frames found. The
+extra frames are set to zero. Each <i>uintptr\_t</i> is a pc of the callstack.
+The calls from within the malloc debug library are automatically removed.
+
+For 32 bit systems, <i>size\_t</i> and <i>uintptr\_t</i> are both 4 byte values.
+
+For 64 bit systems, <i>size\_t</i> and <i>uintptr\_t</i> are both 8 byte values.
+
+The total number of these structures returned in <i>info</i> is
+<i>overall\_size</i> divided by <i>info\_size</i>.
+
+Note, the size value in each allocation data structure will have bit 31 set
+if this allocation was created by the Zygote process. This helps to distinguish
+between native allocations created by the application.
diff --git a/libc/malloc_debug/TrackData.cpp b/libc/malloc_debug/TrackData.cpp
index c9828d0..18f428b 100644
--- a/libc/malloc_debug/TrackData.cpp
+++ b/libc/malloc_debug/TrackData.cpp
@@ -44,9 +44,10 @@
#include "malloc_debug.h"
#include "TrackData.h"
-void TrackData::GetList(std::vector<const Header*>* list) {
- ScopedDisableDebugCalls disable;
+TrackData::TrackData(DebugData* debug_data) : OptionData(debug_data) {
+}
+void TrackData::GetList(std::vector<const Header*>* list) {
for (const auto& header : headers_) {
list->push_back(header);
}
@@ -59,8 +60,6 @@
}
void TrackData::Add(const Header* header, bool backtrace_found) {
- ScopedDisableDebugCalls disable;
-
pthread_mutex_lock(&mutex_);
if (backtrace_found) {
total_backtrace_allocs_++;
@@ -70,8 +69,6 @@
}
void TrackData::Remove(const Header* header, bool backtrace_found) {
- ScopedDisableDebugCalls disable;
-
pthread_mutex_lock(&mutex_);
headers_.erase(header);
if (backtrace_found) {
@@ -81,26 +78,22 @@
}
bool TrackData::Contains(const Header* header) {
- ScopedDisableDebugCalls disable;
-
pthread_mutex_lock(&mutex_);
bool found = headers_.count(header);
pthread_mutex_unlock(&mutex_);
return found;
}
-void TrackData::DisplayLeaks(DebugData& debug) {
- ScopedDisableDebugCalls disable;
-
+void TrackData::DisplayLeaks() {
std::vector<const Header*> list;
GetList(&list);
size_t track_count = 0;
for (const auto& header : list) {
error_log("+++ %s leaked block of size %zu at %p (leak %zu of %zu)", getprogname(),
- header->real_size(), debug.GetPointer(header), ++track_count, list.size());
- if (debug.config().options & BACKTRACE) {
- BacktraceHeader* back_header = debug.GetAllocBacktrace(header);
+ header->real_size(), debug_->GetPointer(header), ++track_count, list.size());
+ if (debug_->config().options & BACKTRACE) {
+ BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);
if (back_header->num_frames > 0) {
error_log("Backtrace at time of allocation:");
backtrace_log(&back_header->frames[0], back_header->num_frames);
@@ -110,15 +103,15 @@
}
}
-void TrackData::GetInfo(DebugData& debug, uint8_t** info, size_t* overall_size,
- size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
+void TrackData::GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
+ size_t* total_memory, size_t* backtrace_size) {
ScopedPthreadMutexLocker scoped(&mutex_);
if (headers_.size() == 0 || total_backtrace_allocs_ == 0) {
return;
}
- *backtrace_size = debug.config().backtrace_frames;
+ *backtrace_size = debug_->config().backtrace_frames;
*info_size = sizeof(size_t) * 2 + sizeof(uintptr_t) * *backtrace_size;
*info = reinterpret_cast<uint8_t*>(g_dispatch->calloc(*info_size, total_backtrace_allocs_));
if (*info == nullptr) {
@@ -131,7 +124,7 @@
uint8_t* data = *info;
for (const auto& header : list) {
- BacktraceHeader* back_header = debug.GetAllocBacktrace(header);
+ BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);
if (back_header->num_frames > 0) {
memcpy(data, &header->size, sizeof(size_t));
memcpy(&data[sizeof(size_t)], &back_header->num_frames, sizeof(size_t));
diff --git a/libc/malloc_debug/TrackData.h b/libc/malloc_debug/TrackData.h
index 1234316..fcd8f2a 100644
--- a/libc/malloc_debug/TrackData.h
+++ b/libc/malloc_debug/TrackData.h
@@ -37,14 +37,16 @@
#include <private/bionic_macros.h>
+#include "OptionData.h"
+
// Forward declarations.
struct Header;
struct Config;
class DebugData;
-class TrackData {
+class TrackData : public OptionData {
public:
- TrackData() = default;
+ TrackData(DebugData* debug_data);
virtual ~TrackData() = default;
void GetList(std::vector<const Header*>* list);
@@ -55,10 +57,10 @@
bool Contains(const Header *header);
- void GetInfo(DebugData& debug, uint8_t** info, size_t* overall_size,
- size_t* info_size, size_t* total_memory, size_t* backtrace_size);
+ void GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
+ size_t* total_memory, size_t* backtrace_size);
- void DisplayLeaks(DebugData& debug);
+ void DisplayLeaks();
void PrepareFork() { pthread_mutex_lock(&mutex_); }
void PostForkParent() { pthread_mutex_unlock(&mutex_); }
diff --git a/libc/malloc_debug/debug_disable.cpp b/libc/malloc_debug/debug_disable.cpp
index af0264b..b80ba8c 100644
--- a/libc/malloc_debug/debug_disable.cpp
+++ b/libc/malloc_debug/debug_disable.cpp
@@ -32,7 +32,6 @@
#include "debug_disable.h"
#include "debug_log.h"
-extern DebugData* g_debug;
pthread_key_t g_disable_key;
bool DebugCallsDisabled() {
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 1ee7689..5da5b88 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -114,8 +114,6 @@
}
static void LogTagError(const Header* header, const void* pointer, const char* name) {
- ScopedDisableDebugCalls disable;
-
error_log(LOG_DIVIDER);
if (header->tag == DEBUG_FREE_TAG) {
error_log("+++ ALLOCATION %p USED AFTER FREE (%s)", pointer, name);
@@ -165,7 +163,6 @@
if (g_debug->config().options & BACKTRACE) {
BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
if (g_debug->backtrace->enabled()) {
- ScopedDisableDebugCalls disable;
back_header->num_frames = backtrace_get(
&back_header->frames[0], g_debug->config().backtrace_frames);
backtrace_found = back_header->num_frames > 0;
@@ -217,11 +214,11 @@
}
if (g_debug->config().options & FREE_TRACK) {
- g_debug->free_track->VerifyAll(*g_debug);
+ g_debug->free_track->VerifyAll();
}
if (g_debug->config().options & LEAK_TRACK) {
- g_debug->track->DisplayLeaks(*g_debug);
+ g_debug->track->DisplayLeaks();
}
DebugDisableSet(true);
@@ -257,32 +254,37 @@
return;
}
- g_debug->track->GetInfo(*g_debug, info, overall_size, info_size, total_memory, backtrace_size);
+ g_debug->track->GetInfo(info, overall_size, info_size, total_memory, backtrace_size);
}
void debug_free_malloc_leak_info(uint8_t* info) {
g_dispatch->free(info);
}
-size_t debug_malloc_usable_size(void* pointer) {
- if (DebugCallsDisabled() || !g_debug->need_header() || pointer == nullptr) {
+static size_t internal_malloc_usable_size(void* pointer) {
+ if (g_debug->need_header()) {
+ Header* header = g_debug->GetHeader(pointer);
+ if (header->tag != DEBUG_TAG) {
+ LogTagError(header, pointer, "malloc_usable_size");
+ return 0;
+ }
+
+ return header->usable_size;
+ } else {
return g_dispatch->malloc_usable_size(pointer);
}
-
- Header* header = g_debug->GetHeader(pointer);
- if (header->tag != DEBUG_TAG) {
- LogTagError(header, pointer, "malloc_usable_size");
- return 0;
- }
-
- return header->usable_size;
}
-void* debug_malloc(size_t size) {
- if (DebugCallsDisabled()) {
- return g_dispatch->malloc(size);
+size_t debug_malloc_usable_size(void* pointer) {
+ if (DebugCallsDisabled() || pointer == nullptr) {
+ return g_dispatch->malloc_usable_size(pointer);
}
+ ScopedDisableDebugCalls disable;
+ return internal_malloc_usable_size(pointer);
+}
+
+static void *internal_malloc(size_t size) {
if (size == 0) {
size = 1;
}
@@ -312,7 +314,7 @@
}
if (pointer != nullptr && g_debug->config().options & FILL_ON_ALLOC) {
- size_t bytes = debug_malloc_usable_size(pointer);
+ size_t bytes = internal_malloc_usable_size(pointer);
size_t fill_bytes = g_debug->config().fill_on_alloc_bytes;
bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
memset(pointer, g_debug->config().fill_alloc_value, bytes);
@@ -320,11 +322,16 @@
return pointer;
}
-void debug_free(void* pointer) {
- if (DebugCallsDisabled() || pointer == nullptr) {
- return g_dispatch->free(pointer);
+void* debug_malloc(size_t size) {
+ if (DebugCallsDisabled()) {
+ return g_dispatch->malloc(size);
}
+ ScopedDisableDebugCalls disable;
+ return internal_malloc(size);
+}
+
+static void internal_free(void* pointer) {
void* free_pointer = pointer;
size_t bytes;
Header* header;
@@ -337,13 +344,13 @@
free_pointer = header->orig_pointer;
if (g_debug->config().options & FRONT_GUARD) {
- if (!g_debug->front_guard->Valid(*g_debug, header)) {
- g_debug->front_guard->LogFailure(*g_debug, header);
+ if (!g_debug->front_guard->Valid(header)) {
+ g_debug->front_guard->LogFailure(header);
}
}
if (g_debug->config().options & REAR_GUARD) {
- if (!g_debug->rear_guard->Valid(*g_debug, header)) {
- g_debug->rear_guard->LogFailure(*g_debug, header);
+ if (!g_debug->rear_guard->Valid(header)) {
+ g_debug->rear_guard->LogFailure(header);
}
}
@@ -374,16 +381,26 @@
// frees at the same time and we wind up trying to really free this
// pointer from another thread, while still trying to free it in
// this function.
- g_debug->free_track->Add(*g_debug, header);
+ g_debug->free_track->Add(header);
} else {
g_dispatch->free(free_pointer);
}
}
+void debug_free(void* pointer) {
+ if (DebugCallsDisabled() || pointer == nullptr) {
+ return g_dispatch->free(pointer);
+ }
+ ScopedDisableDebugCalls disable;
+
+ internal_free(pointer);
+}
+
void* debug_memalign(size_t alignment, size_t bytes) {
if (DebugCallsDisabled()) {
return g_dispatch->memalign(alignment, bytes);
}
+ ScopedDisableDebugCalls disable;
if (bytes == 0) {
bytes = 1;
@@ -438,11 +455,12 @@
}
if (pointer != nullptr && g_debug->config().options & FILL_ON_ALLOC) {
- size_t bytes = debug_malloc_usable_size(pointer);
+ size_t bytes = internal_malloc_usable_size(pointer);
size_t fill_bytes = g_debug->config().fill_on_alloc_bytes;
bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
memset(pointer, g_debug->config().fill_alloc_value, bytes);
}
+
return pointer;
}
@@ -450,13 +468,14 @@
if (DebugCallsDisabled()) {
return g_dispatch->realloc(pointer, bytes);
}
+ ScopedDisableDebugCalls disable;
if (pointer == nullptr) {
- return debug_malloc(bytes);
+ return internal_malloc(bytes);
}
if (bytes == 0) {
- debug_free(pointer);
+ internal_free(pointer);
return nullptr;
}
@@ -486,6 +505,7 @@
// Same size, do nothing.
if (real_size == header->real_size()) {
+ // Do not bother recording, this is essentially a nop.
return pointer;
}
@@ -502,11 +522,12 @@
memset(g_debug->GetRearGuard(header), g_debug->config().rear_guard_value,
g_debug->config().rear_guard_bytes);
}
+ // Do not bother recording, this is essentially a nop.
return pointer;
}
// Allocate the new size.
- new_pointer = debug_malloc(bytes);
+ new_pointer = internal_malloc(bytes);
if (new_pointer == nullptr) {
errno = ENOMEM;
return nullptr;
@@ -514,7 +535,7 @@
prev_size = header->usable_size;
memcpy(new_pointer, pointer, prev_size);
- debug_free(pointer);
+ internal_free(pointer);
} else {
prev_size = g_dispatch->malloc_usable_size(pointer);
new_pointer = g_dispatch->realloc(pointer, real_size);
@@ -524,7 +545,7 @@
}
if (g_debug->config().options & FILL_ON_ALLOC) {
- size_t bytes = debug_malloc_usable_size(new_pointer);
+ size_t bytes = internal_malloc_usable_size(new_pointer);
if (bytes > g_debug->config().fill_on_alloc_bytes) {
bytes = g_debug->config().fill_on_alloc_bytes;
}
@@ -541,6 +562,7 @@
if (DebugCallsDisabled()) {
return g_dispatch->calloc(nmemb, bytes);
}
+ ScopedDisableDebugCalls disable;
size_t size;
if (__builtin_mul_overflow(nmemb, bytes, &size)) {
@@ -645,6 +667,7 @@
if (DebugCallsDisabled() || pointer == nullptr) {
return 0;
}
+ ScopedDisableDebugCalls disable;
if (g_debug->need_header()) {
Header* header;
diff --git a/libc/include/sys/_errdefs.h b/libc/private/bionic_errdefs.h
similarity index 100%
rename from libc/include/sys/_errdefs.h
rename to libc/private/bionic_errdefs.h
diff --git a/libc/include/sys/_sigdefs.h b/libc/private/bionic_sigdefs.h
similarity index 100%
rename from libc/include/sys/_sigdefs.h
rename to libc/private/bionic_sigdefs.h
diff --git a/libc/tools/check-symbols-glibc.py b/libc/tools/check-symbols-glibc.py
index c5dbdcf..43531c0 100755
--- a/libc/tools/check-symbols-glibc.py
+++ b/libc/tools/check-symbols-glibc.py
@@ -178,6 +178,23 @@
'_ctype_',
'__libc_init',
])
+# POSIX has some stuff that's too stupid for words (a64l) or not actually
+# implemented in glibc unless you count always failing with ENOSYS as
+# being implemented (fattach).
+in_posix_and_glibc_but_actually_dead = set([
+ 'a64l',
+ 'fattach',
+ 'fdetach',
+ 'getmsg',
+ 'getpmsg',
+ 'isastream',
+ 'l64a',
+ 'putmsg',
+ 'putpmsg',
+])
+
+posix = posix - in_posix_and_glibc_but_actually_dead
+glibc = glibc - in_posix_and_glibc_but_actually_dead
if not only_unwanted:
#print 'glibc:'
diff --git a/libc/upstream-netbsd/lib/libc/gen/ftw.c b/libc/upstream-netbsd/lib/libc/gen/ftw.c
deleted file mode 100644
index a7f6bbd..0000000
--- a/libc/upstream-netbsd/lib/libc/gen/ftw.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/* $NetBSD: ftw.c,v 1.1 2005/12/30 23:07:32 agc Exp $ */
-
-/* From OpenBSD: ftw.c,v 1.2 2003/07/21 21:15:32 millert Exp */
-
-/*
- * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * 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.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-#include <sys/cdefs.h>
-
-#ifndef lint
-__RCSID("$NetBSD: ftw.c,v 1.1 2005/12/30 23:07:32 agc Exp $");
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <fts.h>
-#include <ftw.h>
-#include <limits.h>
-
-int
-ftw(const char *path, int (*fn)(const char *, const struct stat *, int),
- int nfds)
-{
- /* LINTED */
- char * const paths[2] = { __UNCONST(path), NULL };
- FTSENT *cur;
- FTS *ftsp;
- int fnflag, error, sverrno;
-
- /* XXX - nfds is currently unused */
- if (nfds < 1 || nfds > OPEN_MAX) {
- errno = EINVAL;
- return (-1);
- }
-
- ftsp = fts_open(paths, FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
- if (ftsp == NULL)
- return (-1);
- error = 0;
- while ((cur = fts_read(ftsp)) != NULL) {
- switch (cur->fts_info) {
- case FTS_D:
- fnflag = FTW_D;
- break;
- case FTS_DNR:
- fnflag = FTW_DNR;
- break;
- case FTS_DP:
- /* we only visit in preorder */
- continue;
- case FTS_F:
- case FTS_DEFAULT:
- fnflag = FTW_F;
- break;
- case FTS_NS:
- case FTS_NSOK:
- case FTS_SLNONE:
- fnflag = FTW_NS;
- break;
- case FTS_SL:
- fnflag = FTW_SL;
- break;
- case FTS_DC:
- errno = ELOOP;
- /* FALLTHROUGH */
- default:
- error = -1;
- goto done;
- }
- error = fn(cur->fts_path, cur->fts_statp, fnflag);
- if (error != 0)
- break;
- }
-done:
- sverrno = errno;
- if (fts_close(ftsp) != 0 && error == 0)
- error = -1;
- else
- errno = sverrno;
- return (error);
-}
diff --git a/libc/upstream-netbsd/lib/libc/gen/nftw.c b/libc/upstream-netbsd/lib/libc/gen/nftw.c
deleted file mode 100644
index 0e51342..0000000
--- a/libc/upstream-netbsd/lib/libc/gen/nftw.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/* $NetBSD */
-
-/* From OpenBSD: nftw.c,v 1.2 2003/07/21 21:15:32 millert Exp */
-
-/*
- * Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * 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.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-
-#include <sys/cdefs.h>
-
-#ifndef lint
-__RCSID("$NetBSD: nftw.c,v 1.1 2005/12/30 23:07:32 agc Exp $");
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <fts.h>
-#include <ftw.h>
-#include <limits.h>
-
-int
-nftw(const char *path, int (*fn)(const char *, const struct stat *, int,
- struct FTW *), int nfds, int ftwflags)
-{
- /* LINTED */
- char * const paths[2] = { __UNCONST(path), NULL };
- struct FTW f;
- FTSENT *cur;
- FTS *ftsp;
- int ftsflags, fnflag, error, postorder, sverrno;
-
- /* XXX - nfds is currently unused */
- if (nfds < 1 || nfds > OPEN_MAX) {
- errno = EINVAL;
- return (-1);
- }
-
- ftsflags = FTS_COMFOLLOW;
- if (!(ftwflags & FTW_CHDIR))
- ftsflags |= FTS_NOCHDIR;
- if (ftwflags & FTW_MOUNT)
- ftsflags |= FTS_XDEV;
- if (ftwflags & FTW_PHYS)
- ftsflags |= FTS_PHYSICAL;
- postorder = (ftwflags & FTW_DEPTH) != 0;
- ftsp = fts_open(paths, ftsflags, NULL);
- if (ftsp == NULL)
- return (-1);
- error = 0;
- while ((cur = fts_read(ftsp)) != NULL) {
- switch (cur->fts_info) {
- case FTS_D:
- if (postorder)
- continue;
- fnflag = FTW_D;
- break;
- case FTS_DNR:
- fnflag = FTW_DNR;
- break;
- case FTS_DP:
- if (!postorder)
- continue;
- fnflag = FTW_DP;
- break;
- case FTS_F:
- case FTS_DEFAULT:
- fnflag = FTW_F;
- break;
- case FTS_NS:
- case FTS_NSOK:
- fnflag = FTW_NS;
- break;
- case FTS_SL:
- fnflag = FTW_SL;
- break;
- case FTS_SLNONE:
- fnflag = FTW_SLN;
- break;
- case FTS_DC:
- errno = ELOOP;
- /* FALLTHROUGH */
- default:
- error = -1;
- goto done;
- }
- f.base = cur->fts_pathlen - cur->fts_namelen;
- f.level = cur->fts_level;
- error = fn(cur->fts_path, cur->fts_statp, fnflag, &f);
- if (error != 0)
- break;
- }
-done:
- sverrno = errno;
- (void) fts_close(ftsp);
- errno = sverrno;
- return (error);
-}
diff --git a/libc/dns/net/base64.c b/libc/upstream-openbsd/lib/libc/net/base64.c
similarity index 82%
rename from libc/dns/net/base64.c
rename to libc/upstream-openbsd/lib/libc/net/base64.c
index 1886986..e90696d 100644
--- a/libc/dns/net/base64.c
+++ b/libc/upstream-openbsd/lib/libc/net/base64.c
@@ -1,4 +1,4 @@
-/* $NetBSD: base64.c,v 1.8 2002/11/11 01:15:17 thorpej Exp $ */
+/* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */
/*
* Copyright (c) 1996 by Internet Software Consortium.
@@ -42,25 +42,14 @@
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: base64.c,v 1.8 2002/11/11 01:15:17 thorpej Exp $");
-#endif /* LIBC_SCCS and not lint */
-
#include <sys/types.h>
-#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
-#include <assert.h>
#include <ctype.h>
-#ifdef ANDROID_CHANGES
-#include "resolv_private.h"
-#else
#include <resolv.h>
-#endif
#include <stdio.h>
#include <stdlib.h>
@@ -118,9 +107,9 @@
end of the data is performed using the '=' character.
Since all base64 input is an integral number of octets, only the
- -------------------------------------------------
+ -------------------------------------------------
following cases can arise:
-
+
(1) the final quantum of encoding input is an integral
multiple of 24 bits; here, the final unit of encoded
output will be an integral multiple of 4 characters
@@ -141,12 +130,9 @@
size_t targsize;
{
size_t datalength = 0;
- u_char input[3] = { 0, 0, 0 }; /* make compiler happy */
+ u_char input[3];
u_char output[4];
- size_t i;
-
- assert(src != NULL);
- assert(target != NULL);
+ int i;
while (2 < srclength) {
input[0] = *src++;
@@ -154,16 +140,10 @@
input[2] = *src++;
srclength -= 3;
- output[0] = (u_int32_t)input[0] >> 2;
- output[1] = ((u_int32_t)(input[0] & 0x03) << 4) +
- ((u_int32_t)input[1] >> 4);
- output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
- ((u_int32_t)input[2] >> 6);
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
output[3] = input[2] & 0x3f;
- assert(output[0] < 64);
- assert(output[1] < 64);
- assert(output[2] < 64);
- assert(output[3] < 64);
if (datalength + 4 > targsize)
return (-1);
@@ -172,22 +152,17 @@
target[datalength++] = Base64[output[2]];
target[datalength++] = Base64[output[3]];
}
-
+
/* Now we worry about padding. */
if (0 != srclength) {
/* Get what's left. */
input[0] = input[1] = input[2] = '\0';
for (i = 0; i < srclength; i++)
input[i] = *src++;
-
- output[0] = (u_int32_t)input[0] >> 2;
- output[1] = ((u_int32_t)(input[0] & 0x03) << 4) +
- ((u_int32_t)input[1] >> 4);
- output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) +
- ((u_int32_t)input[2] >> 6);
- assert(output[0] < 64);
- assert(output[1] < 64);
- assert(output[2] < 64);
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
if (datalength + 4 > targsize)
return (-1);
@@ -217,17 +192,14 @@
u_char *target;
size_t targsize;
{
- size_t tarindex;
- int state, ch;
+ int tarindex, state, ch;
+ u_char nextbyte;
char *pos;
- assert(src != NULL);
- assert(target != NULL);
-
state = 0;
tarindex = 0;
- while ((ch = (u_char) *src++) != '\0') {
+ while ((ch = (unsigned char)*src++) != '\0') {
if (isspace(ch)) /* Skip whitespace anywhere. */
continue;
@@ -249,24 +221,28 @@
break;
case 1:
if (target) {
- if (tarindex + 1 >= targsize)
+ if (tarindex >= targsize)
return (-1);
- target[tarindex] |=
- (u_int32_t)(pos - Base64) >> 4;
- target[tarindex+1] = ((pos - Base64) & 0x0f)
- << 4 ;
+ target[tarindex] |= (pos - Base64) >> 4;
+ nextbyte = ((pos - Base64) & 0x0f) << 4;
+ if (tarindex + 1 < targsize)
+ target[tarindex+1] = nextbyte;
+ else if (nextbyte)
+ return (-1);
}
tarindex++;
state = 2;
break;
case 2:
if (target) {
- if (tarindex + 1 >= targsize)
+ if (tarindex >= targsize)
return (-1);
- target[tarindex] |=
- (u_int32_t)(pos - Base64) >> 2;
- target[tarindex+1] = ((pos - Base64) & 0x03)
- << 6;
+ target[tarindex] |= (pos - Base64) >> 2;
+ nextbyte = ((pos - Base64) & 0x03) << 6;
+ if (tarindex + 1 < targsize)
+ target[tarindex+1] = nextbyte;
+ else if (nextbyte)
+ return (-1);
}
tarindex++;
state = 3;
@@ -280,8 +256,6 @@
tarindex++;
state = 0;
break;
- default:
- abort();
}
}
@@ -290,8 +264,8 @@
* on a byte boundary, and/or with erroneous trailing characters.
*/
- if (ch == Pad64) { /* We got a pad char. */
- ch = *src++; /* Skip it, get next. */
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = (unsigned char)*src++; /* Skip it, get next. */
switch (state) {
case 0: /* Invalid = in first position */
case 1: /* Invalid = in second position */
@@ -299,13 +273,13 @@
case 2: /* Valid, means one byte of info */
/* Skip any number of spaces. */
- for (; ch != '\0'; ch = (u_char) *src++)
+ for (; ch != '\0'; ch = (unsigned char)*src++)
if (!isspace(ch))
break;
/* Make sure there is another trailing = sign. */
if (ch != Pad64)
return (-1);
- ch = *src++; /* Skip the = */
+ ch = (unsigned char)*src++; /* Skip the = */
/* Fall through to "single trailing =" case. */
/* FALLTHROUGH */
@@ -314,7 +288,7 @@
* We know this char is an =. Is there anything but
* whitespace after it?
*/
- for (; ch != '\0'; ch = (u_char) *src++)
+ for (; ch != '\0'; ch = (unsigned char)*src++)
if (!isspace(ch))
return (-1);
@@ -324,7 +298,8 @@
* zeros. If we don't check them, they become a
* subliminal channel.
*/
- if (target && target[tarindex] != 0)
+ if (target && tarindex < targsize &&
+ target[tarindex] != 0)
return (-1);
}
} else {
diff --git a/libdl/Android.bp b/libdl/Android.bp
index 2aa9b68..84561d9 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -56,5 +56,7 @@
allow_undefined_symbols: true,
system_shared_libs: [],
- sanitize: ["never"],
+ sanitize: {
+ never: true,
+ },
}
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 67c8d08..20efa9a 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -16,8 +16,6 @@
LIBC_N {
global:
- android_init_namespaces;
- android_create_namespace;
dlvsym;
} LIBC;
@@ -27,4 +25,6 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
+ android_init_namespaces;
+ android_create_namespace;
} LIBC_N;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 4d035f5..daf5a86 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -15,8 +15,6 @@
LIBC_N {
global:
- android_init_namespaces;
- android_create_namespace;
dlvsym;
} LIBC;
@@ -26,4 +24,6 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
+ android_init_namespaces;
+ android_create_namespace;
} LIBC_N;
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 67ff64e..79bced3 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -30,8 +30,6 @@
LIBC_N {
global:
- android_init_namespaces;
- android_create_namespace;
dlvsym;
} LIBC;
@@ -41,4 +39,6 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
+ android_init_namespaces;
+ android_create_namespace;
} LIBC_N;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 4d035f5..daf5a86 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -15,8 +15,6 @@
LIBC_N {
global:
- android_init_namespaces;
- android_create_namespace;
dlvsym;
} LIBC;
@@ -26,4 +24,6 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
+ android_init_namespaces;
+ android_create_namespace;
} LIBC_N;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 4d035f5..daf5a86 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -15,8 +15,6 @@
LIBC_N {
global:
- android_init_namespaces;
- android_create_namespace;
dlvsym;
} LIBC;
@@ -26,4 +24,6 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
+ android_init_namespaces;
+ android_create_namespace;
} LIBC_N;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 4d035f5..daf5a86 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -15,8 +15,6 @@
LIBC_N {
global:
- android_init_namespaces;
- android_create_namespace;
dlvsym;
} LIBC;
@@ -26,4 +24,6 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
+ android_init_namespaces;
+ android_create_namespace;
} LIBC_N;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 4d035f5..daf5a86 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -15,8 +15,6 @@
LIBC_N {
global:
- android_init_namespaces;
- android_create_namespace;
dlvsym;
} LIBC;
@@ -26,4 +24,6 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
+ android_init_namespaces;
+ android_create_namespace;
} LIBC_N;
diff --git a/libm/Android.bp b/libm/Android.bp
index 52249c9..27ea1c1 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -314,7 +314,9 @@
system_shared_libs: ["libc"],
native_coverage: bionic_coverage,
- sanitize: ["never"],
+ sanitize: {
+ never: true,
+ },
multilib: {
lib32: {
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 93fab8f..0fdf90d 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -110,6 +110,7 @@
void add_soinfos(const soinfo::soinfo_list_t& soinfos) {
for (auto si : soinfos) {
add_soinfo(si);
+ si->add_secondary_namespace(this);
}
}
@@ -146,6 +147,7 @@
static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
+static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
static soinfo* solist;
static soinfo* sonext;
@@ -286,6 +288,14 @@
g_soinfo_links_allocator.free(entry);
}
+LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
+ return g_namespace_list_allocator.alloc();
+}
+
+void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
+ g_namespace_list_allocator.free(entry);
+}
+
static soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
struct stat* file_stat, off64_t file_offset,
uint32_t rtld_flags) {
@@ -349,9 +359,6 @@
sonext = prev;
}
- // remove from the namespace
- si->get_namespace()->remove_soinfo(si);
-
si->~soinfo();
g_soinfo_allocator.free(si);
}
@@ -843,7 +850,7 @@
}
this->rtld_flags_ = rtld_flags;
- this->namespace_ = ns;
+ this->primary_namespace_ = ns;
}
soinfo::~soinfo() {
@@ -1003,6 +1010,7 @@
g_soinfo_allocator.protect_all(protection);
g_soinfo_links_allocator.protect_all(protection);
g_namespace_allocator.protect_all(protection);
+ g_namespace_list_allocator.protect_all(protection);
}
static size_t ref_count_;
@@ -2122,7 +2130,7 @@
TRACE("deprecated (old format of soinfo): %s needs to unload %s",
si->get_realpath(), library_name);
- soinfo* needed = find_library(si->get_namespace(),
+ soinfo* needed = find_library(si->get_primary_namespace(),
library_name, RTLD_NOLOAD, nullptr, nullptr);
if (needed != nullptr) {
@@ -2172,6 +2180,10 @@
return std::string(sym_name) + ", version " + sym_ver;
}
+static android_namespace_t* get_caller_namespace(soinfo* caller) {
+ return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
+}
+
void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
// Use basic string manipulation calls to avoid snprintf.
// snprintf indirectly calls pthread_getspecific to get the size of a buffer.
@@ -2208,7 +2220,7 @@
return nullptr;
}
- android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
+ android_namespace_t* ns = get_caller_namespace(caller);
if (extinfo != nullptr) {
if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
@@ -2302,7 +2314,7 @@
soinfo* found = nullptr;
const ElfW(Sym)* sym = nullptr;
soinfo* caller = find_containing_library(caller_addr);
- android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
+ android_namespace_t* ns = get_caller_namespace(caller);
version_info vi_instance;
version_info* vi = nullptr;
@@ -2415,7 +2427,7 @@
soinfo* caller_soinfo = find_containing_library(caller_addr);
android_namespace_t* caller_ns = caller_soinfo != nullptr ?
- caller_soinfo->get_namespace() :
+ caller_soinfo->get_primary_namespace() :
g_anonymous_namespace;
ProtectedDataGuard guard;
@@ -3023,10 +3035,6 @@
// DT_FINI should be called after DT_FINI_ARRAY if both are present.
call_function("DT_FINI", fini_func_);
-
- // This is needed on second call to dlopen
- // after library has been unloaded with RTLD_NODELETE
- constructors_called = false;
}
void soinfo::add_child(soinfo* child) {
@@ -3054,9 +3062,20 @@
});
});
- // 2. Once everything untied - clear local lists.
+ // 2. Remove from the primary namespace
+ primary_namespace_->remove_soinfo(this);
+ primary_namespace_ = nullptr;
+
+ // 3. Remove from secondary namespaces
+ secondary_namespaces_.for_each([&](android_namespace_t* ns) {
+ ns->remove_soinfo(this);
+ });
+
+
+ // 4. Once everything untied - clear local lists.
parents_.clear();
children_.clear();
+ secondary_namespaces_.clear();
}
dev_t soinfo::get_st_dev() const {
@@ -3190,14 +3209,19 @@
return g_empty_runpath;
}
-android_namespace_t* soinfo::get_namespace() {
+android_namespace_t* soinfo::get_primary_namespace() {
if (has_min_version(3)) {
- return namespace_;
+ return primary_namespace_;
}
return &g_default_namespace;
}
+void soinfo::add_secondary_namespace(android_namespace_t* secondary_ns) {
+ CHECK(has_min_version(3));
+ secondary_namespaces_.push_back(secondary_ns);
+}
+
ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
return call_ifunc_resolver(s->st_value + load_bias);
@@ -3220,7 +3244,7 @@
}
bool soinfo::can_unload() const {
- return (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0;
+ return !is_linked() || ((get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0);
}
bool soinfo::is_linked() const {
diff --git a/linker/linker.h b/linker/linker.h
index 81f93ac..4e2e0b9 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -114,6 +114,16 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(SoinfoListAllocator);
};
+class NamespaceListAllocator {
+ public:
+ static LinkedListEntry<android_namespace_t>* alloc();
+ static void free(LinkedListEntry<android_namespace_t>* entry);
+
+ private:
+ // unconstructable
+ DISALLOW_IMPLICIT_CONSTRUCTORS(NamespaceListAllocator);
+};
+
class SymbolName {
public:
explicit SymbolName(const char* name)
@@ -166,6 +176,7 @@
struct soinfo {
public:
typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
+ typedef LinkedList<android_namespace_t, NamespaceListAllocator> android_namespace_list_t;
#if defined(__work_around_b_24465209__)
private:
char old_name_[SOINFO_NAME_LEN];
@@ -342,7 +353,8 @@
void set_dt_runpath(const char *);
const std::vector<std::string>& get_dt_runpath() const;
- android_namespace_t* get_namespace();
+ android_namespace_t* get_primary_namespace();
+ void add_secondary_namespace(android_namespace_t* secondary_ns);
void set_mapped_by_caller(bool reserved_map);
bool is_mapped_by_caller() const;
@@ -414,7 +426,8 @@
// version >= 3
std::vector<std::string> dt_runpath_;
- android_namespace_t* namespace_;
+ android_namespace_t* primary_namespace_;
+ android_namespace_list_t secondary_namespaces_;
uintptr_t handle_;
friend soinfo* get_libdl_info();
diff --git a/tests/Android.mk b/tests/Android.mk
index c190428..7292d9d 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -74,9 +74,11 @@
net_if_test.cpp \
netinet_in_test.cpp \
netinet_udp_test.cpp \
+ nl_types_test.cpp \
pthread_test.cpp \
pty_test.cpp \
regex_test.cpp \
+ resolv_test.cpp \
sched_test.cpp \
search_test.cpp \
semaphore_test.cpp \
@@ -102,6 +104,7 @@
sys_personality_test.cpp \
sys_prctl_test.cpp \
sys_procfs_test.cpp \
+ sys_quota_test.cpp \
sys_resource_test.cpp \
sys_select_test.cpp \
sys_sendfile_test.cpp \
@@ -413,7 +416,7 @@
libcutils \
bionic-unit-tests-glibc_ldlibs := \
- -lrt -ldl -lutil \
+ -lresolv -lrt -ldl -lutil \
bionic-unit-tests-glibc_c_includes := \
bionic/libc \
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index bbdc024..87e5dbc 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -959,6 +959,70 @@
dlclose(handle2);
}
+TEST(dlext, ns_shared_dlclose) {
+ std::string path = "libc.so:libc++.so:libdl.so:libm.so";
+
+ const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
+
+ android_set_application_target_sdk_version(42U); // something > 23
+
+ ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
+
+ // preload this library to the default namespace to check if it
+ // is shared later on.
+ void* handle_dlopened =
+ dlopen((lib_path + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
+ ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
+
+ android_namespace_t* ns_isolated_shared =
+ android_create_namespace("private_isolated_shared", nullptr,
+ (lib_path + "/private_namespace_libs").c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
+ nullptr);
+ ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
+
+ // Check if "libnstest_dlopened.so" is loaded (and the same)
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns_isolated_shared;
+
+ void* handle = android_dlopen_ext("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD, &extinfo);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+ ASSERT_TRUE(handle == handle_dlopened);
+ dlclose(handle);
+ dlclose(handle_dlopened);
+
+ // And now check that the library cannot be found by soname (and is no longer loaded)
+ handle = android_dlopen_ext("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD, &extinfo);
+ ASSERT_TRUE(handle == nullptr)
+ << "Error: libnstest_dlopened.so is still accessible in shared namespace";
+
+ handle = android_dlopen_ext((lib_path + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
+ RTLD_NOW | RTLD_NOLOAD, &extinfo);
+ ASSERT_TRUE(handle == nullptr)
+ << "Error: libnstest_dlopened.so is still accessible in shared namespace";
+
+ handle = dlopen("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD);
+ ASSERT_TRUE(handle == nullptr)
+ << "Error: libnstest_dlopened.so is still accessible in default namespace";
+
+ handle = dlopen((lib_path + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
+ RTLD_NOW | RTLD_NOLOAD);
+ ASSERT_TRUE(handle == nullptr)
+ << "Error: libnstest_dlopened.so is still accessible in default namespace";
+
+ // Now lets see if the soinfo area gets reused in the wrong way:
+ // load a library to default namespace.
+ const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
+ void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
+ ASSERT_TRUE(handle_public != nullptr) << dlerror();
+
+ // try to find it in shared namespace
+ handle = android_dlopen_ext(g_public_lib, RTLD_NOW | RTLD_NOLOAD, &extinfo);
+ ASSERT_TRUE(handle == nullptr)
+ << "Error: " << g_public_lib << " is accessible in shared namespace";
+}
+
TEST(dlext, ns_anonymous) {
static const char* root_lib = "libnstest_root.so";
std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 19f9978..748d0ca 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -256,6 +256,21 @@
ASSERT_STREQ("true", is_ctor_called());
dlclose(handle);
}
+
+TEST(dlfcn, ifunc_ctor_call_rtld_lazy) {
+ typedef const char* (*fn_ptr)();
+
+ void* handle = dlopen("libtest_ifunc.so", RTLD_LAZY);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+ fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative"));
+ ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
+ ASSERT_STREQ("false", is_ctor_called());
+
+ is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot"));
+ ASSERT_TRUE(is_ctor_called != nullptr) << dlerror();
+ ASSERT_STREQ("true", is_ctor_called());
+ dlclose(handle);
+}
#endif
TEST(dlfcn, dlopen_check_relocation_dt_needed_order) {
diff --git a/tests/ftw_test.cpp b/tests/ftw_test.cpp
index b7e5bd5..ea494ba 100644
--- a/tests/ftw_test.cpp
+++ b/tests/ftw_test.cpp
@@ -16,6 +16,7 @@
#include <ftw.h>
+#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
@@ -24,6 +25,7 @@
#include "TemporaryFile.h"
+#include <android-base/stringprintf.h>
#include <gtest/gtest.h>
static void MakeTree(const char* root) {
@@ -39,7 +41,7 @@
snprintf(path, sizeof(path), "%s/dangler", root);
ASSERT_EQ(0, symlink("/does-not-exist", path));
snprintf(path, sizeof(path), "%s/symlink", root);
- ASSERT_EQ(0, symlink("sub2", path));
+ ASSERT_EQ(0, symlink("dir/sub", path));
int fd;
snprintf(path, sizeof(path), "%s/regular", root);
@@ -51,8 +53,21 @@
ASSERT_TRUE(fpath != NULL);
ASSERT_TRUE(sb != NULL);
+ // Was it a case where the struct stat we're given is meaningless?
+ if (tflag == FTW_NS || tflag == FTW_SLN) {
+ // If so, double-check that we really can't stat.
+ struct stat sb;
+ EXPECT_EQ(-1, stat(fpath, &sb));
+ return;
+ }
+
+ // Otherwise check that the struct stat matches the type flag.
if (S_ISDIR(sb->st_mode)) {
- EXPECT_TRUE(tflag == FTW_D || tflag == FTW_DNR || tflag == FTW_DP) << fpath;
+ if (access(fpath, R_OK) == 0) {
+ EXPECT_TRUE(tflag == FTW_D || tflag == FTW_DP) << fpath << ' ' << tflag;
+ } else {
+ EXPECT_EQ(FTW_DNR, tflag) << fpath;
+ }
} else if (S_ISLNK(sb->st_mode)) {
EXPECT_EQ(FTW_SL, tflag) << fpath;
} else {
@@ -60,7 +75,7 @@
}
}
-void sanity_check_nftw(const char* fpath, const struct stat* sb, int tflag, struct FTW* ftwbuf) {
+void sanity_check_nftw(const char* fpath, const struct stat* sb, int tflag, FTW* ftwbuf) {
sanity_check_ftw(fpath, sb, tflag);
ASSERT_EQ('/', fpath[ftwbuf->base - 1]) << fpath;
}
@@ -75,12 +90,12 @@
return 0;
}
-int check_nftw(const char* fpath, const struct stat* sb, int tflag, struct FTW* ftwbuf) {
+int check_nftw(const char* fpath, const struct stat* sb, int tflag, FTW* ftwbuf) {
sanity_check_nftw(fpath, sb, tflag, ftwbuf);
return 0;
}
-int check_nftw64(const char* fpath, const struct stat64* sb, int tflag, struct FTW* ftwbuf) {
+int check_nftw64(const char* fpath, const struct stat64* sb, int tflag, FTW* ftwbuf) {
sanity_check_nftw(fpath, reinterpret_cast<const struct stat*>(sb), tflag, ftwbuf);
return 0;
}
@@ -108,3 +123,33 @@
MakeTree(root.dirname);
ASSERT_EQ(0, nftw64(root.dirname, check_nftw64, 128, 0));
}
+
+template <typename StatT>
+static int bug_28197840_ftw(const char* path, const StatT*, int flag) {
+ EXPECT_EQ(strstr(path, "unreadable") != nullptr ? FTW_DNR : FTW_D, flag) << path;
+ return 0;
+}
+
+template <typename StatT>
+static int bug_28197840_nftw(const char* path, const StatT* sb, int flag, FTW*) {
+ return bug_28197840_ftw(path, sb, flag);
+}
+
+TEST(ftw, bug_28197840) {
+ // Drop root for this test, because root can still read directories even if
+ // permissions would imply otherwise.
+ if (getuid() == 0) {
+ passwd* pwd = getpwnam("shell");
+ ASSERT_EQ(0, setuid(pwd->pw_uid));
+ }
+
+ TemporaryDir root;
+
+ std::string path = android::base::StringPrintf("%s/unreadable-directory", root.dirname);
+ ASSERT_EQ(0, mkdir(path.c_str(), 0000)) << path;
+
+ ASSERT_EQ(0, ftw(root.dirname, bug_28197840_ftw<struct stat>, 128));
+ ASSERT_EQ(0, ftw64(root.dirname, bug_28197840_ftw<struct stat64>, 128));
+ ASSERT_EQ(0, nftw(root.dirname, bug_28197840_nftw<struct stat>, 128, FTW_PHYS));
+ ASSERT_EQ(0, nftw64(root.dirname, bug_28197840_nftw<struct stat64>, 128, FTW_PHYS));
+}
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index c81ca58..29cd907 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -122,12 +122,20 @@
check_get_passwd("radio", 1001, TYPE_SYSTEM);
}
-TEST(getpwnam, oem_id_0) {
- check_get_passwd("oem_0", 5000, TYPE_SYSTEM);
+TEST(getpwnam, oem_id_5000) {
+ check_get_passwd("oem_5000", 5000, TYPE_SYSTEM);
}
-TEST(getpwnam, oem_id_999) {
- check_get_passwd("oem_999", 5999, TYPE_SYSTEM);
+TEST(getpwnam, oem_id_5999) {
+ check_get_passwd("oem_5999", 5999, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, oem_id_2900) {
+ check_get_passwd("oem_2900", 2900, TYPE_SYSTEM);
+}
+
+TEST(getpwnam, oem_id_2999) {
+ check_get_passwd("oem_2999", 2999, TYPE_SYSTEM);
}
TEST(getpwnam, app_id_nobody) {
@@ -255,12 +263,20 @@
check_get_group("radio", 1001);
}
-TEST(getgrnam, oem_id_0) {
- check_get_group("oem_0", 5000);
+TEST(getgrnam, oem_id_5000) {
+ check_get_group("oem_5000", 5000);
}
-TEST(getgrnam, oem_id_999) {
- check_get_group("oem_999", 5999);
+TEST(getgrnam, oem_id_5999) {
+ check_get_group("oem_5999", 5999);
+}
+
+TEST(getgrnam, oem_id_2900) {
+ check_get_group("oem_2900", 2900);
+}
+
+TEST(getgrnam, oem_id_2999) {
+ check_get_group("oem_2999", 2999);
}
TEST(getgrnam, app_id_nobody) {
diff --git a/tests/nl_types_test.cpp b/tests/nl_types_test.cpp
new file mode 100644
index 0000000..2e3995b
--- /dev/null
+++ b/tests/nl_types_test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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 <nl_types.h>
+
+#include <errno.h>
+#include <gtest/gtest.h>
+
+TEST(nl_types, smoke) {
+ nl_catd cat = catopen("/does/not/exist", NL_CAT_LOCALE);
+ ASSERT_EQ(reinterpret_cast<nl_catd>(-1), cat);
+
+ ASSERT_STREQ("hello, world!", catgets(cat, NL_SETD, 0, "hello, world!"));
+
+ errno = 0;
+ ASSERT_EQ(-1, catclose(cat));
+ ASSERT_EQ(EBADF, errno);
+}
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 019016d..589cab4 100755
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -24,6 +24,7 @@
#include <signal.h>
#include <stdio.h>
#include <sys/mman.h>
+#include <sys/prctl.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
@@ -422,7 +423,21 @@
SpinFunctionHelper spin_helper;
pthread_t t;
- ASSERT_EQ(0, pthread_create(&t, NULL, spin_helper.GetFunction(), NULL));
+ ASSERT_EQ(0, pthread_create(&t, nullptr, spin_helper.GetFunction(), nullptr));
+ test_pthread_setname_np__pthread_getname_np(t);
+ spin_helper.UnSpin();
+ ASSERT_EQ(0, pthread_join(t, nullptr));
+}
+
+// http://b/28051133: a kernel misfeature means that you can't change the
+// name of another thread if you've set PR_SET_DUMPABLE to 0.
+TEST(pthread, pthread_setname_np__pthread_getname_np__other_PR_SET_DUMPABLE) {
+ ASSERT_EQ(0, prctl(PR_SET_DUMPABLE, 0)) << strerror(errno);
+
+ SpinFunctionHelper spin_helper;
+
+ pthread_t t;
+ ASSERT_EQ(0, pthread_create(&t, nullptr, spin_helper.GetFunction(), nullptr));
test_pthread_setname_np__pthread_getname_np(t);
spin_helper.UnSpin();
ASSERT_EQ(0, pthread_join(t, nullptr));
diff --git a/tests/resolv_test.cpp b/tests/resolv_test.cpp
new file mode 100644
index 0000000..08f9d90
--- /dev/null
+++ b/tests/resolv_test.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <resolv.h>
+
+#include <gtest/gtest.h>
+
+TEST(resolv, b64_pton_28035006) {
+ // Test data from https://groups.google.com/forum/#!topic/mailing.openbsd.tech/w3ACIlklJkI.
+ const char* data =
+ "p1v3+nehH3N3n+/OokzXpsyGF2VVpxIxkjSn3Mv/Sq74OE1iFuVU+K4bQImuVj"
+ "S55RB2fpCpbB8Nye7tzrt6h9YPP3yyJfqORDETGmIB4lveZXA4KDxx50F9rYrO"
+ "dFbTLyWfNBb/8Q2TnD72eY/3Y5P9qwtJwyDL25Tleic8G3g=";
+
+ // This buffer is exactly the right size, but old versions of the BSD code
+ // incorrectly required an extra byte. http://b/28035006.
+ uint8_t buf[128];
+ ASSERT_EQ(128, b64_pton(data, buf, sizeof(buf)));
+}
diff --git a/tests/sys_quota_test.cpp b/tests/sys_quota_test.cpp
new file mode 100644
index 0000000..e23207b
--- /dev/null
+++ b/tests/sys_quota_test.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 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 <sys/quota.h>
+
+#include <gtest/gtest.h>
+
+TEST(sys_quota, quotactl_dqblk) {
+ // We don't even have kernels with CONFIG_QUOTA enabled right now.
+ // This just tests that we can compile reasonable code.
+ dqblk current;
+ quotactl(QCMD(Q_GETQUOTA, USRQUOTA), "/", getuid(), reinterpret_cast<char*>(¤t));
+}
+
+TEST(sys_quota, quotactl_dqinfo) {
+ // We don't even have kernels with CONFIG_QUOTA enabled right now.
+ // This just tests that we can compile reasonable code.
+ dqinfo current;
+ quotactl(QCMD(Q_GETINFO, USRQUOTA), "/", 0, reinterpret_cast<char*>(¤t));
+}