Merge "Add some MTE-related helpers."
diff --git a/benchmarks/stdlib_benchmark.cpp b/benchmarks/stdlib_benchmark.cpp
index 61b51fa..45b953f 100644
--- a/benchmarks/stdlib_benchmark.cpp
+++ b/benchmarks/stdlib_benchmark.cpp
@@ -59,6 +59,41 @@
BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_free_decay1, "AT_COMMON_SIZES");
#endif
+static void CallocFree(benchmark::State& state) {
+ const size_t nbytes = state.range(0);
+ int pagesize = getpagesize();
+
+ for (auto _ : state) {
+ void* ptr;
+ benchmark::DoNotOptimize(ptr = calloc(1, nbytes));
+ MakeAllocationResident(ptr, nbytes, pagesize);
+ free(ptr);
+ }
+
+ state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
+}
+
+static void BM_stdlib_calloc_free_default(benchmark::State& state) {
+#if defined(__BIONIC__)
+ // The default is expected to be a zero decay time.
+ mallopt(M_DECAY_TIME, 0);
+#endif
+
+ CallocFree(state);
+}
+BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_calloc_free_default, "AT_COMMON_SIZES");
+
+#if defined(__BIONIC__)
+static void BM_stdlib_calloc_free_decay1(benchmark::State& state) {
+ mallopt(M_DECAY_TIME, 1);
+
+ CallocFree(state);
+
+ mallopt(M_DECAY_TIME, 0);
+}
+BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_calloc_free_decay1, "AT_COMMON_SIZES");
+#endif
+
static void MallocMultiple(benchmark::State& state, size_t nbytes, size_t numAllocs) {
int pagesize = getpagesize();
void* ptrs[numAllocs];
diff --git a/benchmarks/unistd_benchmark.cpp b/benchmarks/unistd_benchmark.cpp
index d697dfd..f0a3089 100644
--- a/benchmarks/unistd_benchmark.cpp
+++ b/benchmarks/unistd_benchmark.cpp
@@ -14,9 +14,16 @@
* limitations under the License.
*/
+#include <errno.h>
+#include <string.h>
#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
+#include <string>
+
+#include <android-base/stringprintf.h>
#include <benchmark/benchmark.h>
#include "util.h"
@@ -28,3 +35,35 @@
BIONIC_TRIVIAL_BENCHMARK(BM_unistd_gettid, gettid());
#endif
BIONIC_TRIVIAL_BENCHMARK(BM_unistd_gettid_syscall, syscall(__NR_gettid));
+
+// Many native allocators have custom prefork and postfork functions.
+// Measure the fork call to make sure nothing takes too long.
+void BM_unistd_fork_call(benchmark::State& state) {
+ for (auto _ : state) {
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ // Sleep for a little while so that the parent is not interrupted
+ // right away when the process exits.
+ usleep(100);
+ _exit(1);
+ }
+ state.PauseTiming();
+ if (pid == -1) {
+ std::string err = android::base::StringPrintf("Fork failed: %s", strerror(errno));
+ state.SkipWithError(err.c_str());
+ }
+ pid_t wait_pid = waitpid(pid, 0, 0);
+ if (wait_pid != pid) {
+ if (wait_pid == -1) {
+ std::string err = android::base::StringPrintf("waitpid call failed: %s", strerror(errno));
+ state.SkipWithError(err.c_str());
+ } else {
+ std::string err = android::base::StringPrintf(
+ "waitpid return an unknown pid, expected %d, actual %d", pid, wait_pid);
+ state.SkipWithError(err.c_str());
+ }
+ }
+ state.ResumeTiming();
+ }
+}
+BIONIC_BENCHMARK(BM_unistd_fork_call);
diff --git a/libc/Android.bp b/libc/Android.bp
index 78d2e71..0f8ed3e 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1085,7 +1085,7 @@
"bionic/clone.cpp",
"bionic/ctype.cpp",
"bionic/dirent.cpp",
- "bionic/dup2.cpp",
+ "bionic/dup.cpp",
"bionic/environ.cpp",
"bionic/error.cpp",
"bionic/eventfd_read.cpp",
@@ -1094,7 +1094,9 @@
"bionic/faccessat.cpp",
"bionic/fchmod.cpp",
"bionic/fchmodat.cpp",
+ "bionic/fcntl.cpp",
"bionic/fdsan.cpp",
+ "bionic/fdtrack.cpp",
"bionic/ffs.cpp",
"bionic/fgetxattr.cpp",
"bionic/flistxattr.cpp",
@@ -1163,6 +1165,7 @@
"bionic/realpath.cpp",
"bionic/reboot.cpp",
"bionic/recv.cpp",
+ "bionic/recvmsg.cpp",
"bionic/rename.cpp",
"bionic/rmdir.cpp",
"bionic/scandir.cpp",
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 517d5f9..1343e4e 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -123,12 +123,12 @@
ssize_t readv(int, const struct iovec*, int) all
ssize_t writev(int, const struct iovec*, int) all
int __fcntl64:fcntl64(int, int, void*) lp32
-int fcntl(int, int, void*) lp64
+int __fcntl:fcntl(int, int, void*) lp64
int flock(int, int) all
int __fchmod:fchmod(int, mode_t) all
-int dup(int) all
int pipe2(int*, int) all
-int dup3(int, int, int) all
+int __dup:dup(int) all
+int __dup3:dup3(int, int, int) all
int fsync(int) all
int fdatasync(int) all
int fchown:fchown32(int, uid_t, gid_t) arm,x86
@@ -254,9 +254,9 @@
int shutdown(int, int) arm,arm64,mips,mips64,x86_64
int setsockopt(int, int, int, const void*, socklen_t) arm,arm64,mips,mips64,x86_64
int getsockopt(int, int, int, void*, socklen_t*) arm,arm64,mips,mips64,x86_64
-ssize_t recvmsg(int, struct msghdr*, unsigned int) arm,arm64,mips,mips64,x86_64
+ssize_t __recvmsg:recvmsg(int, struct msghdr*, unsigned int) arm,arm64,mips,mips64,x86_64
ssize_t __sendmsg:sendmsg(int, const struct msghdr*, unsigned int) arm,arm64,mips,mips64,x86_64
-int recvmmsg(int, struct mmsghdr*, unsigned int, int, const struct timespec*) arm,arm64,mips,mips64,x86_64
+int __recvmmsg:recvmmsg(int, struct mmsghdr*, unsigned int, int, const struct timespec*) arm,arm64,mips,mips64,x86_64
int __sendmmsg:sendmmsg(int, struct mmsghdr*, unsigned int, int) arm,arm64,mips,mips64,x86_64
# sockets for x86. These are done as an "indexed" call to socketcall syscall.
@@ -273,9 +273,9 @@
int setsockopt:socketcall:14(int, int, int, const void*, socklen_t) x86
int getsockopt:socketcall:15(int, int, int, void*, socklen_t*) x86
int __sendmsg:socketcall:16(int, const struct msghdr*, unsigned int) x86
-int recvmsg:socketcall:17(int, struct msghdr*, unsigned int) x86
+int __recvmsg:socketcall:17(int, struct msghdr*, unsigned int) x86
int __accept4:socketcall:18(int, struct sockaddr*, socklen_t*, int) x86
-int recvmmsg:socketcall:19(int, struct mmsghdr*, unsigned int, int, const struct timespec*) x86
+int __recvmmsg:socketcall:19(int, struct mmsghdr*, unsigned int, int, const struct timespec*) x86
int __sendmmsg:socketcall:20(int, struct mmsghdr*, unsigned int, int) x86
# scheduler & real-time
diff --git a/libc/bionic/NetdClientDispatch.cpp b/libc/bionic/NetdClientDispatch.cpp
index 463ef36..e6f4a97 100644
--- a/libc/bionic/NetdClientDispatch.cpp
+++ b/libc/bionic/NetdClientDispatch.cpp
@@ -18,6 +18,8 @@
#include <sys/socket.h>
+#include "private/bionic_fdtrack.h"
+
#ifdef __i386__
#define __socketcall __attribute__((__cdecl__))
#else
@@ -53,7 +55,7 @@
};
int accept4(int fd, sockaddr* addr, socklen_t* addr_length, int flags) {
- return __netdClientDispatch.accept4(fd, addr, addr_length, flags);
+ return FDTRACK_CREATE(__netdClientDispatch.accept4(fd, addr, addr_length, flags));
}
int connect(int fd, const sockaddr* addr, socklen_t addr_length) {
@@ -74,5 +76,5 @@
}
int socket(int domain, int type, int protocol) {
- return __netdClientDispatch.socket(domain, type, protocol);
+ return FDTRACK_CREATE(__netdClientDispatch.socket(domain, type, protocol));
}
diff --git a/libc/bionic/dup2.cpp b/libc/bionic/dup.cpp
similarity index 83%
rename from libc/bionic/dup2.cpp
rename to libc/bionic/dup.cpp
index 98c5646..d9e89a5 100644
--- a/libc/bionic/dup2.cpp
+++ b/libc/bionic/dup.cpp
@@ -29,6 +29,15 @@
#include <fcntl.h>
#include <unistd.h>
+#include "private/bionic_fdtrack.h"
+
+extern "C" int __dup(int old_fd);
+extern "C" int __dup3(int old_fd, int new_fd, int flags);
+
+int dup(int old_fd) {
+ return FDTRACK_CREATE(__dup(old_fd));
+}
+
int dup2(int old_fd, int new_fd) {
// If old_fd is equal to new_fd and a valid file descriptor, dup2 returns
// old_fd without closing it. This is not true of dup3, so we have to
@@ -40,5 +49,9 @@
return old_fd;
}
- return dup3(old_fd, new_fd, 0);
+ return FDTRACK_CREATE(__dup3(old_fd, new_fd, 0));
+}
+
+int dup3(int old_fd, int new_fd, int flags) {
+ return FDTRACK_CREATE(__dup3(old_fd, new_fd, flags));
}
diff --git a/libc/bionic/fcntl.cpp b/libc/bionic/fcntl.cpp
new file mode 100644
index 0000000..c508131
--- /dev/null
+++ b/libc/bionic/fcntl.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 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 <stdarg.h>
+#include <fcntl.h>
+
+#include "private/bionic_fdtrack.h"
+
+#if defined(__LP64__)
+
+extern "C" int __fcntl(int fd, int cmd, ...);
+
+int fcntl(int fd, int cmd, ...) {
+ va_list args;
+ va_start(args, cmd);
+
+ // This is a bit sketchy, especially because arg can be an int, but all of our
+ // supported 64-bit ABIs pass arg in a register.
+ void* arg = va_arg(args, void*);
+ va_end(args);
+
+ int rc = __fcntl(fd, cmd, arg);
+ if (cmd == F_DUPFD) {
+ return FDTRACK_CREATE_NAME("F_DUPFD", rc);
+ } else if (cmd == F_DUPFD_CLOEXEC) {
+ return FDTRACK_CREATE_NAME("F_DUPFD_CLOEXEC", rc);
+ }
+ return rc;
+}
+
+#else
+
+extern "C" int __fcntl64(int, int, ...);
+
+// For fcntl we use the fcntl64 system call to signal that we're using struct flock64.
+int fcntl(int fd, int cmd, ...) {
+ va_list ap;
+
+ va_start(ap, cmd);
+ void* arg = va_arg(ap, void*);
+ va_end(ap);
+
+ if (cmd == F_DUPFD) {
+ return FDTRACK_CREATE_NAME("F_DUPFD", __fcntl64(fd, cmd, arg));
+ } else if (cmd == F_DUPFD_CLOEXEC) {
+ return FDTRACK_CREATE_NAME("F_DUPFD_CLOEXEC", __fcntl64(fd, cmd, arg));
+ }
+ return __fcntl64(fd, cmd, arg);
+}
+
+#endif
diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp
index d4ac71c..ebc680f 100644
--- a/libc/bionic/fdsan.cpp
+++ b/libc/bionic/fdsan.cpp
@@ -43,6 +43,7 @@
#include <platform/bionic/reserved_signals.h>
#include <sys/system_properties.h>
+#include "private/bionic_fdtrack.h"
#include "private/bionic_globals.h"
#include "private/bionic_inline_raise.h"
#include "pthread_internal.h"
@@ -245,6 +246,7 @@
}
int android_fdsan_close_with_tag(int fd, uint64_t expected_tag) {
+ FDTRACK_CLOSE(fd);
FdEntry* fde = GetFdEntry(fd);
if (!fde) {
return __close(fd);
diff --git a/libc/bionic/fdtrack.cpp b/libc/bionic/fdtrack.cpp
new file mode 100644
index 0000000..1123512
--- /dev/null
+++ b/libc/bionic/fdtrack.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 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 <stdatomic.h>
+
+#include <platform/bionic/fdtrack.h>
+#include <platform/bionic/reserved_signals.h>
+
+#include "private/bionic_fdtrack.h"
+#include "private/bionic_tls.h"
+#include "private/bionic_globals.h"
+
+_Atomic(android_fdtrack_hook_t) __android_fdtrack_hook;
+
+bool android_fdtrack_get_enabled() {
+ return !__get_bionic_tls().fdtrack_disabled;
+}
+
+bool android_fdtrack_set_enabled(bool new_value) {
+ auto& tls = __get_bionic_tls();
+ bool prev = !tls.fdtrack_disabled;
+ tls.fdtrack_disabled = !new_value;
+ return prev;
+}
+
+bool android_fdtrack_compare_exchange_hook(android_fdtrack_hook_t* expected,
+ android_fdtrack_hook_t value) {
+ return atomic_compare_exchange_strong(&__android_fdtrack_hook, expected, value);
+}
+
+void __libc_init_fdtrack() {
+ // Register a no-op signal handler.
+ signal(BIONIC_SIGNAL_FDTRACK, [](int) {});
+}
diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp
index 2de1bc7..f08e582 100644
--- a/libc/bionic/legacy_32_bit_support.cpp
+++ b/libc/bionic/legacy_32_bit_support.cpp
@@ -37,27 +37,17 @@
#include <sys/vfs.h>
#include <unistd.h>
+#include "private/bionic_fdtrack.h"
+
#if defined(__LP64__)
#error This code is only needed on 32-bit systems!
#endif
// System calls we need.
-extern "C" int __fcntl64(int, int, void*);
extern "C" int __llseek(int, unsigned long, unsigned long, off64_t*, int);
extern "C" int __preadv64(int, const struct iovec*, int, long, long);
extern "C" int __pwritev64(int, const struct iovec*, int, long, long);
-// For fcntl we use the fcntl64 system call to signal that we're using struct flock64.
-int fcntl(int fd, int cmd, ...) {
- va_list ap;
-
- va_start(ap, cmd);
- void* arg = va_arg(ap, void*);
- va_end(ap);
-
- return __fcntl64(fd, cmd, arg);
-}
-
// For lseek64 we need to use the llseek system call which splits the off64_t in two and
// returns the off64_t result via a pointer because 32-bit kernels can't return 64-bit results.
off64_t lseek64(int fd, off64_t off, int whence) {
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index e4106e9..12628f7 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -104,6 +104,7 @@
__system_properties_init(); // Requires 'environ'.
__libc_init_fdsan(); // Requires system properties (for debug.fdsan).
+ __libc_init_fdtrack();
SetDefaultHeapTaggingLevel();
}
diff --git a/libc/bionic/open.cpp b/libc/bionic/open.cpp
index 222e5d3..bd8685a 100644
--- a/libc/bionic/open.cpp
+++ b/libc/bionic/open.cpp
@@ -31,6 +31,7 @@
#include <stdlib.h>
#include <unistd.h>
+#include "private/bionic_fdtrack.h"
#include "private/bionic_fortify.h"
extern "C" int __openat(int, const char*, int, int);
@@ -62,13 +63,13 @@
va_end(args);
}
- return __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), mode);
+ return FDTRACK_CREATE(__openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), mode));
}
__strong_alias(open64, open);
int __open_2(const char* pathname, int flags) {
if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
- return __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0);
+ return FDTRACK_CREATE_NAME("open", __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0));
}
int openat(int fd, const char *pathname, int flags, ...) {
@@ -81,11 +82,11 @@
va_end(args);
}
- return __openat(fd, pathname, force_O_LARGEFILE(flags), mode);
+ return FDTRACK_CREATE_NAME("openat", __openat(fd, pathname, force_O_LARGEFILE(flags), mode));
}
__strong_alias(openat64, openat);
int __openat_2(int fd, const char* pathname, int flags) {
if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
- return __openat(fd, pathname, force_O_LARGEFILE(flags), 0);
+ return FDTRACK_CREATE_NAME("openat", __openat(fd, pathname, force_O_LARGEFILE(flags), 0));
}
diff --git a/libc/bionic/recvmsg.cpp b/libc/bionic/recvmsg.cpp
new file mode 100644
index 0000000..003f43d
--- /dev/null
+++ b/libc/bionic/recvmsg.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 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 <string.h>
+#include <sys/socket.h>
+
+#include <async_safe/log.h>
+
+#include "private/bionic_fdtrack.h"
+
+extern "C" ssize_t __recvmsg(int __fd, struct msghdr* __msg, int __flags);
+extern "C" int __recvmmsg(int __fd, struct mmsghdr* __msgs, unsigned int __msg_count, int __flags,
+ const struct timespec* __timeout);
+
+static inline __attribute__((artificial)) __attribute__((always_inline)) void track_fds(
+ struct msghdr* msg, const char* function_name) {
+ if (!__android_fdtrack_hook) {
+ return;
+ }
+
+ for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ if (cmsg->cmsg_type != SCM_RIGHTS) {
+ continue;
+ }
+
+ if (cmsg->cmsg_len <= sizeof(struct cmsghdr)) {
+ continue;
+ }
+
+ size_t data_length = cmsg->cmsg_len - sizeof(struct cmsghdr);
+ if (data_length % sizeof(int) != 0) {
+ async_safe_fatal("invalid cmsg length: %zu", data_length);
+ }
+
+ for (size_t offset = 0; offset < data_length; offset += sizeof(int)) {
+ int fd;
+ memcpy(&fd, CMSG_DATA(cmsg) + offset, sizeof(int));
+ FDTRACK_CREATE_NAME(function_name, fd);
+ }
+ }
+}
+
+ssize_t recvmsg(int __fd, struct msghdr* __msg, int __flags) {
+ ssize_t rc = __recvmsg(__fd, __msg, __flags);
+ if (rc == -1) {
+ return -1;
+ }
+ track_fds(__msg, "recvmsg");
+ return rc;
+}
+
+int recvmmsg(int __fd, struct mmsghdr* __msgs, unsigned int __msg_count, int __flags,
+ const struct timespec* __timeout) {
+ int rc = __recvmmsg(__fd, __msgs, __msg_count, __flags, __timeout);
+ if (rc == -1) {
+ return -1;
+ }
+ for (int i = 0; i < rc; ++i) {
+ track_fds(&__msgs[i].msg_hdr, "recvmmsg");
+ }
+ return rc;
+}
diff --git a/libc/include/.clang-format b/libc/include/.clang-format
new file mode 100644
index 0000000..e384528
--- /dev/null
+++ b/libc/include/.clang-format
@@ -0,0 +1 @@
+DisableFormat: true
diff --git a/libc/bionic/dup2.cpp b/libc/include/bits/flock.h
similarity index 67%
copy from libc/bionic/dup2.cpp
copy to libc/include/bits/flock.h
index 98c5646..7c452ad 100644
--- a/libc/bionic/dup2.cpp
+++ b/libc/include/bits/flock.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,19 +26,41 @@
* SUCH DAMAGE.
*/
-#include <fcntl.h>
-#include <unistd.h>
+#pragma once
-int dup2(int old_fd, int new_fd) {
- // If old_fd is equal to new_fd and a valid file descriptor, dup2 returns
- // old_fd without closing it. This is not true of dup3, so we have to
- // handle this case ourselves.
- if (old_fd == new_fd) {
- if (fcntl(old_fd, F_GETFD) == -1) {
- return -1;
- }
- return old_fd;
- }
+/**
+ * @file bits/flock.h
+ * @brief struct flock.
+ */
- return dup3(old_fd, new_fd, 0);
-}
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+#define __FLOCK64_BODY \
+ short l_type; \
+ short l_whence; \
+ off64_t l_start; \
+ off64_t l_len; \
+ pid_t l_pid; \
+
+#if defined(__USE_FILE_OFFSET64) || defined(__LP64__)
+#define __FLOCK_BODY __FLOCK64_BODY
+#else
+#define __FLOCK_BODY \
+ short l_type; \
+ short l_whence; \
+ off_t l_start; \
+ off_t l_len; \
+ pid_t l_pid; \
+
+#endif
+
+struct flock { __FLOCK_BODY };
+struct flock64 { __FLOCK64_BODY };
+
+#undef __FLOCK_BODY
+#undef __FLOCK64_BODY
+
+__END_DECLS
diff --git a/libc/bionic/dup2.cpp b/libc/include/bits/flock64.h
similarity index 73%
copy from libc/bionic/dup2.cpp
copy to libc/include/bits/flock64.h
index 98c5646..95500b9 100644
--- a/libc/bionic/dup2.cpp
+++ b/libc/include/bits/flock64.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,19 +26,6 @@
* SUCH DAMAGE.
*/
-#include <fcntl.h>
-#include <unistd.h>
+#pragma once
-int dup2(int old_fd, int new_fd) {
- // If old_fd is equal to new_fd and a valid file descriptor, dup2 returns
- // old_fd without closing it. This is not true of dup3, so we have to
- // handle this case ourselves.
- if (old_fd == new_fd) {
- if (fcntl(old_fd, F_GETFD) == -1) {
- return -1;
- }
- return old_fd;
- }
-
- return dup3(old_fd, new_fd, 0);
-}
+/* Empty. */
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 23a58d6..1ea94e6 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -51,14 +51,32 @@
__BEGIN_DECLS
-#ifdef __LP64__
+#if defined(__LP64__)
+
/* LP64 kernels don't have F_*64 defines because their flock is 64-bit. */
+
/** Flag for flock(). */
#define F_GETLK64 F_GETLK
/** Flag for flock(). */
#define F_SETLK64 F_SETLK
/** Flag for flock(). */
#define F_SETLKW64 F_SETLKW
+
+#elif defined(__USE_FILE_OFFSET64)
+
+/* For _FILE_OFFSET_BITS=64, redirect the constants to the off64_t variants. */
+
+#undef F_GETLK
+#undef F_SETLK
+#undef F_SETLKW
+
+/** Flag for flock(). */
+#define F_GETLK F_GETLK64
+/** Flag for flock(). */
+#define F_SETLK F_SETLK64
+/** Flag for flock(). */
+#define F_SETLKW F_SETLKW64
+
#endif
/** Flag for open(). */
diff --git a/libc/kernel/.clang-format b/libc/kernel/.clang-format
index e384528..39789c8 100644
--- a/libc/kernel/.clang-format
+++ b/libc/kernel/.clang-format
@@ -1 +1,3 @@
DisableFormat: true
+SortIncludes: false
+SortUsingDeclarations: false
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index 967d0c7..463de12 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -90,6 +90,8 @@
kernel_struct_replacements = set(
[
"epoll_event",
+ "flock",
+ "flock64",
"in_addr",
"ip_mreq_source",
"ip_msfilter",
diff --git a/libc/kernel/uapi/asm-generic/fcntl.h b/libc/kernel/uapi/asm-generic/fcntl.h
index aeb1ac6..a2cb5f4 100644
--- a/libc/kernel/uapi/asm-generic/fcntl.h
+++ b/libc/kernel/uapi/asm-generic/fcntl.h
@@ -18,6 +18,8 @@
****************************************************************************/
#ifndef _ASM_GENERIC_FCNTL_H
#define _ASM_GENERIC_FCNTL_H
+#include <bits/flock64.h>
+#include <bits/flock.h>
#include <linux/types.h>
#define O_ACCMODE 00000003
#define O_RDONLY 00000000
@@ -145,26 +147,10 @@
#ifndef __ARCH_FLOCK_PAD
#define __ARCH_FLOCK_PAD
#endif
-struct flock {
- short l_type;
- short l_whence;
- __kernel_off_t l_start;
- __kernel_off_t l_len;
- __kernel_pid_t l_pid;
- __ARCH_FLOCK_PAD
-};
#endif
#ifndef HAVE_ARCH_STRUCT_FLOCK64
#ifndef __ARCH_FLOCK64_PAD
#define __ARCH_FLOCK64_PAD
#endif
-struct flock64 {
- short l_type;
- short l_whence;
- __kernel_loff_t l_start;
- __kernel_loff_t l_len;
- __kernel_pid_t l_pid;
- __ARCH_FLOCK64_PAD
-};
#endif
#endif
diff --git a/libc/kernel/uapi/asm-mips/asm/fcntl.h b/libc/kernel/uapi/asm-mips/asm/fcntl.h
index 91835f2..8aef90d 100644
--- a/libc/kernel/uapi/asm-mips/asm/fcntl.h
+++ b/libc/kernel/uapi/asm-mips/asm/fcntl.h
@@ -18,6 +18,7 @@
****************************************************************************/
#ifndef _UAPI_ASM_FCNTL_H
#define _UAPI_ASM_FCNTL_H
+#include <bits/flock.h>
#include <asm/sgidefs.h>
#define O_APPEND 0x0008
#define O_DSYNC 0x0010
@@ -43,15 +44,6 @@
#endif
#if _MIPS_SIM != _MIPS_SIM_ABI64
#include <linux/types.h>
-struct flock {
- short l_type;
- short l_whence;
- __kernel_off_t l_start;
- __kernel_off_t l_len;
- long l_sysid;
- __kernel_pid_t l_pid;
- long pad[4];
-};
#define HAVE_ARCH_STRUCT_FLOCK
#endif
#include <asm-generic/fcntl.h>
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 2710fb2..2ca4b21 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1752,6 +1752,9 @@
__system_property_set_filename;
__system_property_update;
android_fdsan_get_fd_table;
+ android_fdtrack_compare_exchange_hook; # llndk
+ android_fdtrack_get_enabled; # llndk
+ android_fdtrack_set_enabled; # llndk
android_net_res_stats_get_info_for_net;
android_net_res_stats_aggregate;
android_net_res_stats_get_usable_servers;
diff --git a/libc/platform/bionic/fdtrack.h b/libc/platform/bionic/fdtrack.h
new file mode 100644
index 0000000..6eb379b
--- /dev/null
+++ b/libc/platform/bionic/fdtrack.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+// Types of an android_fdtrack_event.
+enum android_fdtrack_event_type {
+ // File descriptor creation: create is the active member of android_fdtrack_event::data.
+ ANDROID_FDTRACK_EVENT_TYPE_CREATE,
+
+ // File descriptor closed.
+ ANDROID_FDTRACK_EVENT_TYPE_CLOSE,
+};
+
+struct android_fdtrack_event {
+ // File descriptor for which this event occurred.
+ int fd;
+
+ // Type of event: this is one of the enumerators of android_fdtrack_event_type.
+ uint8_t type;
+
+ // Data for the event.
+ union {
+ struct {
+ const char* function_name;
+ } create;
+ } data;
+};
+
+// Callback invoked upon file descriptor creation/closure.
+typedef void (*android_fdtrack_hook_t)(struct android_fdtrack_event*);
+
+// Register a hook which is called to track fd lifecycle events.
+bool android_fdtrack_compare_exchange_hook(android_fdtrack_hook_t* expected, android_fdtrack_hook_t value) __INTRODUCED_IN(30);
+
+// Enable/disable fdtrack *on the current thread*.
+// This is primarily useful when performing operations which you don't want to track
+// (e.g. when emitting already-recorded information).
+bool android_fdtrack_get_enabled() __INTRODUCED_IN(30);
+bool android_fdtrack_set_enabled(bool new_value) __INTRODUCED_IN(30);
+
+__END_DECLS
diff --git a/libc/platform/bionic/reserved_signals.h b/libc/platform/bionic/reserved_signals.h
index 7634b27..4ac6455 100644
--- a/libc/platform/bionic/reserved_signals.h
+++ b/libc/platform/bionic/reserved_signals.h
@@ -42,14 +42,16 @@
// 36 (__SIGRTMIN + 4) platform profilers (heapprofd, traced_perf)
// 37 (__SIGRTMIN + 5) coverage (libprofile-extras)
// 38 (__SIGRTMIN + 6) heapprofd ART managed heap dumps
+// 39 (__SIGRTMIN + 7) fdtrack
//
// If you change this, also change __ndk_legacy___libc_current_sigrtmin
// in <android/legacy_signal_inlines.h> to match.
#define BIONIC_SIGNAL_DEBUGGER __SIGRTMIN + 3
#define BIONIC_SIGNAL_PROFILER __SIGRTMIN + 4
+#define BIONIC_SIGNAL_FDTRACK __SIGRTMIN + 7
-#define __SIGRT_RESERVED 7
+#define __SIGRT_RESERVED 8
static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset, int how) {
int (*block)(sigset64_t*, int);
int (*unblock)(sigset64_t*, int);
@@ -77,5 +79,6 @@
unblock(&sigset, __SIGRTMIN + 4);
unblock(&sigset, __SIGRTMIN + 5);
unblock(&sigset, __SIGRTMIN + 6);
+ unblock(&sigset, __SIGRTMIN + 7);
return sigset;
}
diff --git a/libc/private/bionic_fdtrack.h b/libc/private/bionic_fdtrack.h
new file mode 100644
index 0000000..174ba1d
--- /dev/null
+++ b/libc/private/bionic_fdtrack.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <stdatomic.h>
+
+#include "platform/bionic/fdtrack.h"
+
+#include "bionic/pthread_internal.h"
+#include "private/bionic_tls.h"
+#include "private/ErrnoRestorer.h"
+
+extern "C" _Atomic(android_fdtrack_hook_t) __android_fdtrack_hook;
+
+// Macro to record file descriptor creation.
+// e.g.:
+// int socket(int domain, int type, int protocol) {
+// return FDTRACK_CREATE_NAME("socket", __socket(domain, type, protocol));
+// }
+#define FDTRACK_CREATE_NAME(name, fd_value) \
+ ({ \
+ int __fd = (fd_value); \
+ if (__fd != -1 && __predict_false(__android_fdtrack_hook)) { \
+ bionic_tls& tls = __get_bionic_tls(); \
+ /* fdtrack_disabled is only true during reentrant calls. */ \
+ if (!__predict_false(tls.fdtrack_disabled)) { \
+ ErrnoRestorer r; \
+ tls.fdtrack_disabled = true; \
+ android_fdtrack_event event; \
+ event.fd = __fd; \
+ event.type = ANDROID_FDTRACK_EVENT_TYPE_CREATE; \
+ event.data.create.function_name = name; \
+ __android_fdtrack_hook(&event); \
+ tls.fdtrack_disabled = false; \
+ } \
+ } \
+ __fd; \
+ })
+
+// Macro to record file descriptor creation, with the current function's name.
+// e.g.:
+// int socket(int domain, int type, int protocol) {
+// return FDTRACK_CREATE_NAME(__socket(domain, type, protocol));
+// }
+#define FDTRACK_CREATE(fd_value) FDTRACK_CREATE_NAME(__func__, (fd_value))
+
+// Macro to record file descriptor closure.
+// Note that this does not actually close the file descriptor.
+#define FDTRACK_CLOSE(fd_value) \
+ ({ \
+ int __fd = (fd_value); \
+ if (__fd != -1 && __predict_false(__android_fdtrack_hook)) { \
+ bionic_tls& tls = __get_bionic_tls(); \
+ if (!__predict_false(tls.fdtrack_disabled)) { \
+ int saved_errno = errno; \
+ tls.fdtrack_disabled = true; \
+ android_fdtrack_event event; \
+ event.fd = __fd; \
+ event.type = ANDROID_FDTRACK_EVENT_TYPE_CLOSE; \
+ __android_fdtrack_hook(&event); \
+ tls.fdtrack_disabled = false; \
+ errno = saved_errno; \
+ } \
+ } \
+ __fd; \
+ })
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index 8997ceb..4cc9bbe 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -100,6 +100,7 @@
__LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals();
__LIBC_HIDDEN__ void __libc_init_fdsan();
+__LIBC_HIDDEN__ void __libc_init_fdtrack();
__LIBC_HIDDEN__ void __libc_init_profiling_handlers();
__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals);
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index bb5c67b..80d645a 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -128,6 +128,9 @@
group_state_t group;
passwd_state_t passwd;
+ char fdtrack_disabled;
+ char padding[3];
+
// Initialize the main thread's final object using its bootstrap object.
void copy_from_bootstrap(const bionic_tls* boot __attribute__((unused))) {
// Nothing in bionic_tls needs to be preserved in the transition to the
diff --git a/libc/upstream-freebsd/.clang-format b/libc/upstream-freebsd/.clang-format
index e384528..39789c8 100644
--- a/libc/upstream-freebsd/.clang-format
+++ b/libc/upstream-freebsd/.clang-format
@@ -1 +1,3 @@
DisableFormat: true
+SortIncludes: false
+SortUsingDeclarations: false
diff --git a/libc/upstream-netbsd/.clang-format b/libc/upstream-netbsd/.clang-format
index e384528..39789c8 100644
--- a/libc/upstream-netbsd/.clang-format
+++ b/libc/upstream-netbsd/.clang-format
@@ -1 +1,3 @@
DisableFormat: true
+SortIncludes: false
+SortUsingDeclarations: false
diff --git a/libc/upstream-openbsd/.clang-format b/libc/upstream-openbsd/.clang-format
index e384528..39789c8 100644
--- a/libc/upstream-openbsd/.clang-format
+++ b/libc/upstream-openbsd/.clang-format
@@ -1 +1,3 @@
DisableFormat: true
+SortIncludes: false
+SortUsingDeclarations: false
diff --git a/libfdtrack/.clang-format b/libfdtrack/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libfdtrack/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libfdtrack/Android.bp b/libfdtrack/Android.bp
new file mode 100644
index 0000000..fd13512
--- /dev/null
+++ b/libfdtrack/Android.bp
@@ -0,0 +1,18 @@
+cc_library_shared {
+ name: "libfdtrack",
+ srcs: ["fdtrack.cpp"],
+ stl: "libc++_static",
+
+ header_libs: ["bionic_libc_platform_headers"],
+ static_libs: [
+ "libasync_safe",
+ "libbase",
+ "libunwindstack",
+ "liblzma",
+ "liblog",
+ ],
+ version_script: "libfdtrack.map.txt",
+
+ allow_undefined_symbols: true,
+ recovery_available: true,
+}
diff --git a/libfdtrack/fdtrack.cpp b/libfdtrack/fdtrack.cpp
new file mode 100644
index 0000000..831a50d
--- /dev/null
+++ b/libfdtrack/fdtrack.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 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 <inttypes.h>
+
+#include <array>
+#include <mutex>
+#include <vector>
+
+#include <android/fdsan.h>
+#include <bionic/fdtrack.h>
+
+#include <android-base/no_destructor.h>
+#include <android-base/thread_annotations.h>
+#include <async_safe/log.h>
+#include <bionic/reserved_signals.h>
+#include <unwindstack/LocalUnwinder.h>
+
+struct FdEntry {
+ std::mutex mutex;
+ std::vector<unwindstack::LocalFrameData> backtrace GUARDED_BY(mutex);
+};
+
+extern "C" void fdtrack_dump();
+static void fd_hook(android_fdtrack_event* event);
+
+// Backtraces for the first 4k file descriptors ought to be enough to diagnose an fd leak.
+static constexpr size_t kFdTableSize = 4096;
+static constexpr size_t kStackDepth = 10;
+
+static bool installed = false;
+static std::array<FdEntry, kFdTableSize> stack_traces;
+static unwindstack::LocalUnwinder& Unwinder() {
+ static android::base::NoDestructor<unwindstack::LocalUnwinder> unwinder;
+ return *unwinder.get();
+}
+
+__attribute__((constructor)) static void ctor() {
+ signal(BIONIC_SIGNAL_FDTRACK, [](int) { fdtrack_dump(); });
+ if (Unwinder().Init()) {
+ android_fdtrack_hook_t expected = nullptr;
+ installed = android_fdtrack_compare_exchange_hook(&expected, &fd_hook);
+ }
+}
+
+__attribute__((destructor)) static void dtor() {
+ if (installed) {
+ android_fdtrack_hook_t expected = &fd_hook;
+ android_fdtrack_compare_exchange_hook(&expected, nullptr);
+ }
+}
+
+FdEntry* GetFdEntry(int fd) {
+ if (fd >= 0 && fd < static_cast<int>(kFdTableSize)) {
+ return &stack_traces[fd];
+ }
+ return nullptr;
+}
+
+static void fd_hook(android_fdtrack_event* event) {
+ if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CREATE) {
+ if (FdEntry* entry = GetFdEntry(event->fd); entry) {
+ std::lock_guard<std::mutex> lock(entry->mutex);
+ entry->backtrace.clear();
+ Unwinder().Unwind(&entry->backtrace, kStackDepth);
+ }
+ } else if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CLOSE) {
+ if (FdEntry* entry = GetFdEntry(event->fd); entry) {
+ std::lock_guard<std::mutex> lock(entry->mutex);
+ entry->backtrace.clear();
+ }
+ }
+}
+
+void fdtrack_dump() {
+ if (!installed) {
+ async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack not installed");
+ } else {
+ async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack dumping...");
+ }
+
+ bool prev = android_fdtrack_set_enabled(false);
+ for (int fd = 0; fd < static_cast<int>(stack_traces.size()); ++fd) {
+ FdEntry* entry = GetFdEntry(fd);
+ if (!entry) {
+ continue;
+ }
+
+ if (!entry->mutex.try_lock()) {
+ async_safe_format_log(ANDROID_LOG_WARN, "fdtrack", "fd %d locked, skipping", fd);
+ continue;
+ }
+
+ if (entry->backtrace.empty()) {
+ continue;
+ }
+
+ uint64_t fdsan_owner = android_fdsan_get_owner_tag(fd);
+
+ if (fdsan_owner != 0) {
+ async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (owner = %#" PRIx64 ")", fd,
+ fdsan_owner);
+ } else {
+ async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (unowned)", fd);
+ }
+
+ const size_t frame_skip = 2;
+ for (size_t i = frame_skip; i < entry->backtrace.size(); ++i) {
+ auto& frame = entry->backtrace[i];
+ async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", " %zu: %s+%" PRIu64, i - frame_skip,
+ frame.function_name.c_str(), frame.function_offset);
+ }
+
+ entry->mutex.unlock();
+ }
+ android_fdtrack_set_enabled(prev);
+}
diff --git a/libfdtrack/libfdtrack.map.txt b/libfdtrack/libfdtrack.map.txt
new file mode 100644
index 0000000..7a54c35
--- /dev/null
+++ b/libfdtrack/libfdtrack.map.txt
@@ -0,0 +1,6 @@
+LIBFDTRACK {
+ global:
+ fdtrack_dump;
+ local:
+ *;
+};
diff --git a/libm/upstream-freebsd/.clang-format b/libm/upstream-freebsd/.clang-format
index e384528..39789c8 100644
--- a/libm/upstream-freebsd/.clang-format
+++ b/libm/upstream-freebsd/.clang-format
@@ -1 +1,3 @@
DisableFormat: true
+SortIncludes: false
+SortUsingDeclarations: false
diff --git a/libm/upstream-netbsd/.clang-format b/libm/upstream-netbsd/.clang-format
index e384528..39789c8 100644
--- a/libm/upstream-netbsd/.clang-format
+++ b/libm/upstream-netbsd/.clang-format
@@ -1 +1,3 @@
DisableFormat: true
+SortIncludes: false
+SortUsingDeclarations: false
diff --git a/tests/Android.bp b/tests/Android.bp
index 6320eea..e530132 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -98,7 +98,9 @@
"eventfd_test.cpp",
"fcntl_test.cpp",
"fdsan_test.cpp",
+ "fdtrack_test.cpp",
"fenv_test.cpp",
+ "_FILE_OFFSET_BITS_test.cpp",
"float_test.cpp",
"ftw_test.cpp",
"getauxval_test.cpp",
diff --git a/libc/bionic/dup2.cpp b/tests/_FILE_OFFSET_BITS_test.cpp
similarity index 75%
copy from libc/bionic/dup2.cpp
copy to tests/_FILE_OFFSET_BITS_test.cpp
index 98c5646..cbdb369 100644
--- a/libc/bionic/dup2.cpp
+++ b/tests/_FILE_OFFSET_BITS_test.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,19 +26,22 @@
* SUCH DAMAGE.
*/
+#define _FILE_OFFSET_BITS 64
+
+#include <gtest/gtest.h>
+
#include <fcntl.h>
-#include <unistd.h>
-int dup2(int old_fd, int new_fd) {
- // If old_fd is equal to new_fd and a valid file descriptor, dup2 returns
- // old_fd without closing it. This is not true of dup3, so we have to
- // handle this case ourselves.
- if (old_fd == new_fd) {
- if (fcntl(old_fd, F_GETFD) == -1) {
- return -1;
- }
- return old_fd;
- }
+TEST(fcntl, f_getlk_FOB64) {
+ int fd = open("/proc/version", O_RDONLY);
+ ASSERT_TRUE(fd != -1);
- return dup3(old_fd, new_fd, 0);
+ struct flock check_lock;
+ check_lock.l_type = F_WRLCK;
+ check_lock.l_start = 0;
+ check_lock.l_whence = SEEK_SET;
+ check_lock.l_len = 0;
+
+ ASSERT_EQ(0, fcntl(fd, F_GETLK, &check_lock));
+ close(fd);
}
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index d7dce31..a8a4cc5 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -148,6 +148,20 @@
ASSERT_EQ(4, sb.st_size);
}
+TEST(fcntl, f_getlk) {
+ int fd = open("/proc/version", O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ struct flock check_lock;
+ check_lock.l_type = F_WRLCK;
+ check_lock.l_start = 0;
+ check_lock.l_whence = SEEK_SET;
+ check_lock.l_len = 0;
+
+ ASSERT_EQ(0, fcntl(fd, F_GETLK, &check_lock));
+ close(fd);
+}
+
TEST(fcntl, f_getlk64) {
int fd = open64("/proc/version", O_RDONLY);
ASSERT_TRUE(fd != -1);
@@ -158,9 +172,7 @@
check_lock.l_whence = SEEK_SET;
check_lock.l_len = 0;
- int rc = fcntl(fd, F_GETLK64, &check_lock);
- ASSERT_EQ(0, rc);
-
+ ASSERT_EQ(0, fcntl(fd, F_GETLK64, &check_lock));
close(fd);
}
diff --git a/tests/fdtrack_test.cpp b/tests/fdtrack_test.cpp
new file mode 100644
index 0000000..fca92ce
--- /dev/null
+++ b/tests/fdtrack_test.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2020 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 <gtest/gtest.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if defined(__BIONIC__)
+#include "platform/bionic/fdtrack.h"
+#endif
+
+#include <vector>
+
+#include <android-base/unique_fd.h>
+
+#if defined(__BIONIC__)
+std::vector<android_fdtrack_event> FdtrackRun(void (*func)()) {
+ // Each bionic test is run in separate process, so we can safely use a static here.
+ static std::vector<android_fdtrack_event> events;
+ events.clear();
+
+ android_fdtrack_hook_t previous = nullptr;
+ android_fdtrack_hook_t hook = [](android_fdtrack_event* event) {
+ events.push_back(*event);
+ };
+
+ if (!android_fdtrack_compare_exchange_hook(&previous, hook)) {
+ errx(1, "failed to exchange hook: previous hook was %p", previous);
+ }
+
+ if (previous) {
+ errx(1, "hook was already registered?");
+ abort();
+ }
+
+ func();
+
+ if (!android_fdtrack_compare_exchange_hook(&hook, nullptr)) {
+ errx(1, "failed to reset hook");
+ }
+
+ return std::move(events);
+}
+#endif
+
+TEST(fdtrack, open) {
+#if defined(__BIONIC__)
+ static int fd = -1;
+ auto events = FdtrackRun([]() { fd = open("/dev/null", O_WRONLY | O_CLOEXEC); });
+ ASSERT_NE(-1, fd);
+ ASSERT_EQ(1U, events.size());
+ ASSERT_EQ(fd, events[0].fd);
+ ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CREATE, events[0].type);
+ ASSERT_STREQ("open", events[0].data.create.function_name);
+#endif
+}
+
+TEST(fdtrack, close) {
+#if defined(__BIONIC__)
+ static int fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
+ ASSERT_NE(-1, fd);
+
+ auto events = FdtrackRun([]() { close(fd); });
+ ASSERT_EQ(1U, events.size());
+ ASSERT_EQ(fd, events[0].fd);
+ ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CLOSE, events[0].type);
+#endif
+}
+
+TEST(fdtrack, enable_disable) {
+#if defined(__BIONIC__)
+ static int fd1 = -1;
+ static int fd2 = -1;
+ static int fd3 = -1;
+
+ auto events = FdtrackRun([]() {
+ if (!android_fdtrack_get_enabled()) {
+ errx(1, "fdtrack is disabled");
+ }
+ fd1 = open("/dev/null", O_WRONLY | O_CLOEXEC);
+ android_fdtrack_set_enabled(false);
+ fd2 = open("/dev/null", O_WRONLY | O_CLOEXEC);
+ android_fdtrack_set_enabled(true);
+ fd3 = open("/dev/null", O_WRONLY | O_CLOEXEC);
+ });
+
+ if (fd1 == -1 || fd2 == -1 || fd3 == -1) {
+ errx(1, "failed to open /dev/null");
+ }
+
+ ASSERT_EQ(2U, events.size());
+
+ ASSERT_EQ(fd1, events[0].fd);
+ ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CREATE, events[0].type);
+ ASSERT_STREQ("open", events[0].data.create.function_name);
+
+ ASSERT_EQ(fd3, events[1].fd);
+ ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CREATE, events[1].type);
+ ASSERT_STREQ("open", events[1].data.create.function_name);
+#endif
+}
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index ef2f895..6620cdb 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -829,6 +829,63 @@
#endif
}
+// Jemalloc doesn't pass this test right now, so leave it as disabled.
+TEST(malloc, DISABLED_alloc_after_fork) {
+ // Both of these need to be a power of 2.
+ static constexpr size_t kMinAllocationSize = 8;
+ static constexpr size_t kMaxAllocationSize = 2097152;
+
+ static constexpr size_t kNumAllocatingThreads = 5;
+ static constexpr size_t kNumForkLoops = 100;
+
+ std::atomic_bool stop;
+
+ // Create threads that simply allocate and free different sizes.
+ std::vector<std::thread*> threads;
+ for (size_t i = 0; i < kNumAllocatingThreads; i++) {
+ std::thread* t = new std::thread([&stop] {
+ while (!stop) {
+ for (size_t size = kMinAllocationSize; size <= kMaxAllocationSize; size <<= 1) {
+ void* ptr = malloc(size);
+ if (ptr == nullptr) {
+ return;
+ }
+ // Make sure this value is not optimized away.
+ asm volatile("" : : "r,m"(ptr) : "memory");
+ free(ptr);
+ }
+ }
+ });
+ threads.push_back(t);
+ }
+
+ // Create a thread to fork and allocate.
+ for (size_t i = 0; i < kNumForkLoops; i++) {
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ for (size_t size = kMinAllocationSize; size <= kMaxAllocationSize; size <<= 1) {
+ void* ptr = malloc(size);
+ ASSERT_TRUE(ptr != nullptr);
+ // Make sure this value is not optimized away.
+ asm volatile("" : : "r,m"(ptr) : "memory");
+ // Make sure we can touch all of the allocation.
+ memset(ptr, 0x1, size);
+ ASSERT_LE(size, malloc_usable_size(ptr));
+ free(ptr);
+ }
+ _exit(10);
+ }
+ ASSERT_NE(-1, pid);
+ AssertChildExited(pid, 10);
+ }
+
+ stop = true;
+ for (auto thread : threads) {
+ thread->join();
+ delete thread;
+ }
+}
+
TEST(android_mallopt, error_on_unexpected_option) {
#if defined(__BIONIC__)
const int unrecognized_option = -1;