Add a tool to track down fd leaks.
Add a hook that's called upon file descriptor creation to libc, and a library that uses it to capture backtraces for file descriptor creation, to make it easier to hunt down file descriptor leaks. Currently, this doesn't capture all of the ways of creating a file descriptor, but completeness isn't required for this to be useful as long as leaked file descriptors are created with a function that is tracked. The primary unhandled case is binder, which receives file descriptors as a payload in a not-trivially-parsable byte blob, but there's a chance that the leak we're currently trying to track down isn't of a file descriptor received over binder, so leave that for later. Bug: http://b/140703823 Test: manual Change-Id: I308a14c2e234cdba4207157b634ab6b8bc539dd9
This commit is contained in:
parent
15b4f27853
commit
b7eccd4b15
23 changed files with 713 additions and 29 deletions
|
@ -1103,7 +1103,7 @@ cc_library_static {
|
|||
"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",
|
||||
|
@ -1112,7 +1112,9 @@ cc_library_static {
|
|||
"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",
|
||||
|
@ -1181,6 +1183,7 @@ cc_library_static {
|
|||
"bionic/realpath.cpp",
|
||||
"bionic/reboot.cpp",
|
||||
"bionic/recv.cpp",
|
||||
"bionic/recvmsg.cpp",
|
||||
"bionic/rename.cpp",
|
||||
"bionic/rmdir.cpp",
|
||||
"bionic/scandir.cpp",
|
||||
|
@ -1814,7 +1817,7 @@ cc_library_headers {
|
|||
name: "bionic_libc_platform_headers",
|
||||
visibility: [
|
||||
"//art:__subpackages__",
|
||||
"//bionic/libc:__subpackages__",
|
||||
"//bionic:__subpackages__",
|
||||
"//frameworks:__subpackages__",
|
||||
"//external/perfetto:__subpackages__",
|
||||
"//external/scudo:__subpackages__",
|
||||
|
|
|
@ -123,12 +123,12 @@ int __ioctl:ioctl(int, int, void*) all
|
|||
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 @@ ssize_t recvfrom(int, void*, size_t, unsigned int, struct sockaddr*, sockl
|
|||
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 shutdown:socketcall:13(int, int) x86
|
|||
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
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "private/bionic_fdtrack.h"
|
||||
|
||||
#ifdef __i386__
|
||||
#define __socketcall __attribute__((__cdecl__))
|
||||
#else
|
||||
|
@ -53,7 +55,7 @@ __LIBC_HIDDEN__ NetdClientDispatch __netdClientDispatch __attribute__((aligned(3
|
|||
};
|
||||
|
||||
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 @@ ssize_t sendto(int fd, const void* buf, size_t n, int flags,
|
|||
}
|
||||
|
||||
int socket(int domain, int type, int protocol) {
|
||||
return __netdClientDispatch.socket(domain, type, protocol);
|
||||
return FDTRACK_CREATE(__netdClientDispatch.socket(domain, type, protocol));
|
||||
}
|
||||
|
|
|
@ -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 @@ int dup2(int old_fd, int new_fd) {
|
|||
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));
|
||||
}
|
76
libc/bionic/fcntl.cpp
Normal file
76
libc/bionic/fcntl.cpp
Normal file
|
@ -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
|
|
@ -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 @@ uint64_t android_fdsan_get_tag_value(uint64_t tag) {
|
|||
}
|
||||
|
||||
int android_fdsan_close_with_tag(int fd, uint64_t expected_tag) {
|
||||
FDTRACK_CLOSE(fd);
|
||||
FdEntry* fde = GetFdEntry(fd);
|
||||
if (!fde) {
|
||||
return __close(fd);
|
||||
|
|
60
libc/bionic/fdtrack.cpp
Normal file
60
libc/bionic/fdtrack.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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 <android/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) {});
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -104,6 +104,7 @@ void __libc_init_common() {
|
|||
|
||||
__system_properties_init(); // Requires 'environ'.
|
||||
__libc_init_fdsan(); // Requires system properties (for debug.fdsan).
|
||||
__libc_init_fdtrack();
|
||||
|
||||
SetDefaultHeapTaggingLevel();
|
||||
}
|
||||
|
|
|
@ -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 @@ int open(const char* pathname, int flags, ...) {
|
|||
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 @@ int openat(int fd, const char *pathname, int flags, ...) {
|
|||
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));
|
||||
}
|
||||
|
|
87
libc/bionic/recvmsg.cpp
Normal file
87
libc/bionic/recvmsg.cpp
Normal file
|
@ -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;
|
||||
}
|
73
libc/include/android/fdtrack.h
Normal file
73
libc/include/android/fdtrack.h
Normal file
|
@ -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
|
|
@ -1484,6 +1484,9 @@ LIBC_R { # introduced=R
|
|||
global:
|
||||
__mempcpy_chk;
|
||||
__tls_get_addr; # arm64
|
||||
android_fdtrack_compare_exchange_hook;
|
||||
android_fdtrack_get_enabled;
|
||||
android_fdtrack_set_enabled;
|
||||
call_once;
|
||||
cnd_broadcast;
|
||||
cnd_destroy;
|
||||
|
|
|
@ -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 @@ static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigs
|
|||
unblock(&sigset, __SIGRTMIN + 4);
|
||||
unblock(&sigset, __SIGRTMIN + 5);
|
||||
unblock(&sigset, __SIGRTMIN + 6);
|
||||
unblock(&sigset, __SIGRTMIN + 7);
|
||||
return sigset;
|
||||
}
|
||||
|
|
93
libc/private/bionic_fdtrack.h
Normal file
93
libc/private/bionic_fdtrack.h
Normal file
|
@ -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 <android/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; \
|
||||
})
|
|
@ -100,6 +100,7 @@ struct libc_shared_globals {
|
|||
|
||||
__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);
|
||||
|
|
|
@ -128,6 +128,9 @@ struct bionic_tls {
|
|||
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
|
||||
|
|
1
libfdtrack/.clang-format
Symbolic link
1
libfdtrack/.clang-format
Symbolic link
|
@ -0,0 +1 @@
|
|||
../.clang-format-2
|
18
libfdtrack/Android.bp
Normal file
18
libfdtrack/Android.bp
Normal file
|
@ -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,
|
||||
}
|
127
libfdtrack/fdtrack.cpp
Normal file
127
libfdtrack/fdtrack.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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/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;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(entry->mutex);
|
||||
if (entry->backtrace.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d:", 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);
|
||||
}
|
||||
}
|
||||
android_fdtrack_set_enabled(prev);
|
||||
}
|
6
libfdtrack/libfdtrack.map.txt
Normal file
6
libfdtrack/libfdtrack.map.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
LIBFDTRACK {
|
||||
global:
|
||||
fdtrack_dump;
|
||||
local:
|
||||
*;
|
||||
};
|
|
@ -91,6 +91,7 @@ cc_test_library {
|
|||
"eventfd_test.cpp",
|
||||
"fcntl_test.cpp",
|
||||
"fdsan_test.cpp",
|
||||
"fdtrack_test.cpp",
|
||||
"fenv_test.cpp",
|
||||
"float_test.cpp",
|
||||
"ftw_test.cpp",
|
||||
|
|
120
tests/fdtrack_test.cpp
Normal file
120
tests/fdtrack_test.cpp
Normal file
|
@ -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 <android/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
|
||||
}
|
Loading…
Reference in a new issue