diff options
66 files changed, 1589 insertions, 587 deletions
diff --git a/.clang-format b/.clang-format index b8c642840..7630d1626 100644 --- a/.clang-format +++ b/.clang-format @@ -12,3 +12,4 @@ UseTab: Never PenaltyExcessCharacter: 32 Cpp11BracedListStyle: false +IncludeBlocks: Preserve
\ No newline at end of file diff --git a/benchmarks/property_benchmark.cpp b/benchmarks/property_benchmark.cpp index 77814bf8a..ba54ed1e6 100644 --- a/benchmarks/property_benchmark.cpp +++ b/benchmarks/property_benchmark.cpp @@ -184,7 +184,7 @@ static void BM_property_serial(benchmark::State& state) { size_t i = 0; while (state.KeepRunning()) { - pa.system_properties().Serial(pinfo[i]); + __system_property_serial(pinfo[i]); i = (i + 1) % nprops; } diff --git a/benchmarks/stdlib_benchmark.cpp b/benchmarks/stdlib_benchmark.cpp index ec3f6f248..ffcedf05d 100644 --- a/benchmarks/stdlib_benchmark.cpp +++ b/benchmarks/stdlib_benchmark.cpp @@ -24,11 +24,6 @@ #include <benchmark/benchmark.h> #include "util.h" -#if defined(__BIONIC__) - -#else -#endif - static __always_inline void MakeAllocationResident(void* ptr, size_t nbytes, int pagesize) { uint8_t* data = reinterpret_cast<uint8_t*>(ptr); for (size_t i = 0; i < nbytes; i += pagesize) { diff --git a/docs/native_allocator.md b/docs/native_allocator.md index adfa6ef07..249b1448c 100644 --- a/docs/native_allocator.md +++ b/docs/native_allocator.md @@ -144,6 +144,32 @@ benchmarks. These benchmarks can be built using this command: These benchmarks are only used to verify the speed of the allocator and ignore anything related to RSS and virtual address space consumed. +For all of these benchmark runs, it can be useful to add these two options: + + --benchmark_repetitions=XX + --benchmark_report_aggregates_only=true + +This will run the benchmark XX times and then give a mean, median, and stddev +and helps to get a number that can be compared to the new allocator. + +In addition, there is another option: + + --bionic_cpu=XX + +Which will lock the benchmark to only run on core XX. This also avoids +any issue related to the code migrating from one core to another +with different characteristics. For example, on a big-little cpu, if the +benchmark moves from big to little or vice-versa, this can cause scores +to fluctuate in indeterminte ways. + +For most runs, the best set of options to add is: + + --benchmark_repetitions=10 --benchmark_report_aggregates_only=true --bionic_cpu=3 + +On most phones with a big-little cpu, the third core is the little core. +Choosing to run on the little core can tend to highlight any performance +differences. + #### Allocate/Free Benchmarks These are the benchmarks to verify the allocation speed of a loop doing a single allocation, touching every page in the allocation to make it resident @@ -240,6 +266,18 @@ To run the benchmarks with `mallopt(M_DECAY_TIME, 1)`, use these commands: These numbers should be as performant as the current allocator. +#### mallinfo Benchmark +This benchmark only verifies that mallinfo is still close to the performance +of the current allocator. + +To run the benchmark, use these commands: + + adb shell /data/benchmarktest64/bionic-benchmarks/bionic-benchmarks --benchmark_filter=BM_mallinfo + adb shell /data/benchmarktest/bionic-benchmarks/bionic-benchmarks --benchmark_filter=BM_mallinfo + +Calls to mallinfo are used in ART so a new allocator is required to be +nearly as performant as the current allocator. + ### Memory Trace Benchmarks These benchmarks measure all three axes of a native allocator, RSS, virtual address space consumed, speed of allocation. They are designed to diff --git a/docs/status.md b/docs/status.md index 6968a1800..a1d5332fa 100644 --- a/docs/status.md +++ b/docs/status.md @@ -213,18 +213,31 @@ New libc functions in J (API level 16): * all of <sys/xattr.h>. libc function count over time: - G 803, H 825, I 826, J 846, J-MR1 873, J-MR2 881, K 896, L 1116, M 1181, N 1226, O 1278 +| OS | API level | Function count | +|-------|-----------|----------------| +| J | 16 | 842 | +| J MR1 | 17 | 870 | +| J MR2 | 18 | 878 | +| K | 19 | 893 | +| L | 21 | 1118 | +| M | 23 | 1183 | +| N | 24 | 1228 | +| O | 26 | 1280 | +| P | 28 | 1378 | +| Q | 29 | 1394 | + +Data collected by: ``` -ndk-r17$ for i in `ls -1v platforms/android-*/arch-arm/usr/lib/libc.so` ; do \ - echo $i; nm $i | grep -vw [AbdNnt] | grep -vw B | wc -l ; done +ndk-r21$ for i in `ls -1v platforms/android-*/arch-arm/usr/lib/libc.so` ; do \ + echo $i; nm $i | grep -w T | wc -l ; done ``` ### libm Current libm symbols: https://android.googlesource.com/platform/bionic/+/master/libm/libm.map.txt -0 remaining missing POSIX libm functions. +0 remaining missing C11/POSIX libm functions. New libm functions in O (API level 26): * <complex.h> `clog`/`clogf`, `cpow`/`cpowf` functions. @@ -240,10 +253,6 @@ New libm functions in L (API level 21): New libm functions in J-MR2 (API level 18): * <math.h> `log2`, `log2f`. -libm function count over time: - G 158, J-MR2 164, L 220, M 265, O 284 - - ## Target API level behavioral differences diff --git a/libc/Android.bp b/libc/Android.bp index 3a607c987..697399ddb 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -42,7 +42,6 @@ libc_common_flags = [ "-Wno-deprecated-declarations", "-Wno-gcc-compat", "-Wframe-larger-than=2048", - "-Wimplicit-fallthrough", // Try to catch typical 32-bit assumptions that break with 64-bit pointers. "-Werror=pointer-to-int-cast", @@ -83,6 +82,12 @@ cc_defaults { // lld complains about duplicate symbols in libcrt and libgcc. Suppress the // warning since this is intended right now. ldflags: ["-Wl,-z,muldefs"], + + product_variables: { + experimental_mte: { + cflags: ["-DANDROID_EXPERIMENTAL_MTE"], + }, + }, } // Defaults for native allocator libs/includes to make it @@ -136,19 +141,21 @@ cc_defaults { } // ======================================================== -// libc_stack_protector.a - stack protector code +// libc_bootstrap.a - -fno-stack-protector and -ffreestanding // ======================================================== // -// Code that implements the stack protector (or that runs -// before TLS has been set up) needs to be compiled with -// -fno-stack-protector, since it accesses the stack canary -// TLS slot. +// Code that implements the stack protector (or that runs before TLS has been set up) needs to be +// compiled with -fno-stack-protector, since it accesses the stack canary TLS slot. In the linker, +// some of this code runs before ifunc resolvers have made string.h functions work, so compile with +// -ffreestanding. cc_library_static { srcs: [ "bionic/__libc_init_main_thread.cpp", "bionic/__stack_chk_fail.cpp", + "bionic/bionic_call_ifunc_resolver.cpp", + "bionic/getauxval.cpp", ], arch: { arm64: { @@ -166,20 +173,25 @@ cc_library_static { }, defaults: ["libc_defaults"], - cflags: ["-fno-stack-protector"], - name: "libc_stack_protector", + cflags: ["-fno-stack-protector", "-ffreestanding"], + name: "libc_bootstrap", } -// libc_init_static.cpp also needs to be built without stack protector, -// because it's responsible for setting up TLS for static executables. -// This isn't the case for dynamic executables because the dynamic linker -// has already set up the main thread's TLS. +// libc_init_static.cpp and libc_init_dynamic.cpp need to be built without stack protector. +// libc_init_static.cpp sets up TLS for static executables, and libc_init_dynamic.cpp initializes +// the stack protector global variable. cc_library_static { name: "libc_init_static", defaults: ["libc_defaults"], srcs: ["bionic/libc_init_static.cpp"], - cflags: ["-fno-stack-protector"], + cflags: [ + "-fno-stack-protector", + + // Compile libc_init_static.cpp with -ffreestanding, because some of its code is called + // from the linker before ifunc resolvers have made string.h functions available. + "-ffreestanding", + ], } cc_library_static { @@ -794,12 +806,6 @@ cc_library_static { cc_library_static { defaults: ["libc_defaults"], srcs: [ - // The data that backs getauxval is initialized in the libc init - // functions which are invoked by the linker. If this file is included - // in libc_ndk.a, only one of the copies of the global data will be - // initialized, resulting in nullptr dereferences. - "bionic/getauxval.cpp", - // These require getauxval, which isn't available on older platforms. "bionic/sysconf.cpp", "bionic/vdso.cpp", @@ -1120,7 +1126,6 @@ cc_library_static { "bionic/atof.cpp", "bionic/bionic_allocator.cpp", "bionic/bionic_arc4random.cpp", - "bionic/bionic_call_ifunc_resolver.cpp", "bionic/bionic_futex.cpp", "bionic/bionic_netlink.cpp", "bionic/bionic_systrace.cpp", @@ -1463,6 +1468,7 @@ cc_library_static { whole_static_libs: [ "libc_bionic_ndk", + "libc_bootstrap", "libc_fortify", "libc_freebsd", "libc_freebsd_large_stack", @@ -1470,7 +1476,6 @@ cc_library_static { "libc_netbsd", "libc_openbsd_large_stack", "libc_openbsd_ndk", - "libc_stack_protector", "libc_syscalls", "libc_tzcode", "libm", @@ -1494,6 +1499,7 @@ cc_library_static { whole_static_libs: [ "libc_bionic", "libc_bionic_ndk", + "libc_bootstrap", "libc_dns", "libc_fortify", "libc_freebsd", @@ -1503,7 +1509,6 @@ cc_library_static { "libc_openbsd", "libc_openbsd_large_stack", "libc_openbsd_ndk", - "libc_stack_protector", "libc_syscalls", "libc_tzcode", "libstdc++", @@ -1531,11 +1536,11 @@ cc_library_static { } // ======================================================== -// libc_common_static.a For static binaries. +// libc_static_dispatch.a // ======================================================== cc_library_static { defaults: ["libc_defaults"], - name: "libc_common_static", + name: "libc_static_dispatch", arch: { x86: { @@ -1548,20 +1553,17 @@ cc_library_static { srcs: ["arch-arm64/static_function_dispatch.S"], }, }, - - whole_static_libs: [ - "libc_common", - ], } // ======================================================== -// libc_common_shared.a For shared libraries. +// libc_dynamic_dispatch.a // ======================================================== cc_library_static { defaults: ["libc_defaults"], - name: "libc_common_shared", + name: "libc_dynamic_dispatch", cflags: [ + "-ffreestanding", "-fno-stack-protector", "-fno-jump-tables", ], @@ -1576,9 +1578,31 @@ cc_library_static { srcs: ["arch-arm64/dynamic_function_dispatch.cpp"], }, }, +} + +// ======================================================== +// libc_common_static.a For static binaries. +// ======================================================== +cc_library_static { + defaults: ["libc_defaults"], + name: "libc_common_static", whole_static_libs: [ "libc_common", + "libc_static_dispatch", + ], +} + +// ======================================================== +// libc_common_shared.a For shared libraries. +// ======================================================== +cc_library_static { + defaults: ["libc_defaults"], + name: "libc_common_shared", + + whole_static_libs: [ + "libc_common", + "libc_dynamic_dispatch", ], } @@ -1602,19 +1626,16 @@ cc_library_static { // libc_nomalloc.a // ======================================================== // -// This is a version of the static C library that does not -// include malloc. It's useful in situations when the user wants -// to provide their own malloc implementation, or wants to -// explicitly disallow the use of malloc, such as in the -// dynamic linker. +// This is a version of the static C library used by the dynamic linker that exclude malloc. It also +// excludes functions selected using ifunc's (e.g. for string.h). Link in either +// libc_static_dispatch or libc_dynamic_dispatch to provide those functions. cc_library_static { name: "libc_nomalloc", defaults: ["libc_defaults"], - cflags: ["-DLIBC_STATIC"], whole_static_libs: [ - "libc_common_static", + "libc_common", "libc_init_static", "libc_unwind_static", ], @@ -1731,6 +1752,8 @@ cc_library { strip: { keep_symbols_and_debug_frame: true, }, + + whole_static_libs: [ "libgcc_stripped" ], }, arm64: { version_script: ":libc.arm64.map", diff --git a/libc/arch-x86_64/string/cache.h b/libc/arch-x86_64/string/cache.h index 38acc6e7f..4131509fb 100644 --- a/libc/arch-x86_64/string/cache.h +++ b/libc/arch-x86_64/string/cache.h @@ -28,9 +28,9 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* Values are optimized for Silvermont */ -#define SHARED_CACHE_SIZE (1024*1024) /* Silvermont L2 Cache */ -#define DATA_CACHE_SIZE (24*1024) /* Silvermont L1 Data Cache */ +/* Values are optimized for Core Architecture */ +#define SHARED_CACHE_SIZE (4096*1024) /* Core Architecture L2 Cache */ +#define DATA_CACHE_SIZE (24*1024) /* Core Architecture L1 Data Cache */ -#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2) -#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2) +#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2) +#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2) diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp index 6e1b0de25..94cf1f8e3 100644 --- a/libc/bionic/__libc_init_main_thread.cpp +++ b/libc/bionic/__libc_init_main_thread.cpp @@ -57,7 +57,9 @@ static pthread_internal_t main_thread; // // This is in a file by itself because it needs to be built with // -fno-stack-protector because it's responsible for setting up the main -// thread's TLS (which stack protector relies on). +// thread's TLS (which stack protector relies on). It's also built with +// -ffreestanding because the early init function runs in the linker before +// ifunc resolvers have run. // Do enough setup to: // - Let the dynamic linker invoke system calls (and access errno) @@ -65,7 +67,8 @@ static pthread_internal_t main_thread; // - Allow the stack protector to work (with a zero cookie) // Avoid doing much more because, when this code is called within the dynamic // linker, the linker binary hasn't been relocated yet, so certain kinds of code -// are hazardous, such as accessing non-hidden global variables. +// are hazardous, such as accessing non-hidden global variables or calling +// string.h functions. __BIONIC_WEAK_FOR_NATIVE_BRIDGE extern "C" void __libc_init_main_thread_early(const KernelArgumentBlock& args, bionic_tcb* temp_tcb) { @@ -80,6 +83,23 @@ extern "C" void __libc_init_main_thread_early(const KernelArgumentBlock& args, main_thread.set_cached_pid(main_thread.tid); } +// This code is used both by each new pthread and the code that initializes the main thread. +void __init_tcb(bionic_tcb* tcb, pthread_internal_t* thread) { +#ifdef TLS_SLOT_SELF + // On x86, slot 0 must point to itself so code can read the thread pointer by + // loading %fs:0 or %gs:0. + tcb->tls_slot(TLS_SLOT_SELF) = &tcb->tls_slot(TLS_SLOT_SELF); +#endif + tcb->tls_slot(TLS_SLOT_THREAD_ID) = thread; +} + +void __init_tcb_dtv(bionic_tcb* tcb) { + // Initialize the DTV slot to a statically-allocated empty DTV. The first + // access to a dynamic TLS variable allocates a new DTV. + static const TlsDtv zero_dtv = {}; + __set_tcb_dtv(tcb, const_cast<TlsDtv*>(&zero_dtv)); +} + // Finish initializing the main thread. __BIONIC_WEAK_FOR_NATIVE_BRIDGE extern "C" void __libc_init_main_thread_late() { diff --git a/libc/bionic/bionic_call_ifunc_resolver.cpp b/libc/bionic/bionic_call_ifunc_resolver.cpp index 85228359e..437de78ce 100644 --- a/libc/bionic/bionic_call_ifunc_resolver.cpp +++ b/libc/bionic/bionic_call_ifunc_resolver.cpp @@ -30,14 +30,32 @@ #include <sys/auxv.h> #include <sys/ifunc.h> +#include "private/bionic_auxv.h" + +// This code is called in the linker before it has been relocated, so minimize calls into other +// parts of Bionic. In particular, we won't ever have two ifunc resolvers called concurrently, so +// initializing the ifunc resolver argument doesn't need to be thread-safe. + ElfW(Addr) __bionic_call_ifunc_resolver(ElfW(Addr) resolver_addr) { #if defined(__aarch64__) typedef ElfW(Addr) (*ifunc_resolver_t)(uint64_t, __ifunc_arg_t*); - static __ifunc_arg_t arg = { sizeof(__ifunc_arg_t), getauxval(AT_HWCAP), getauxval(AT_HWCAP2) }; + static __ifunc_arg_t arg; + static bool initialized = false; + if (!initialized) { + initialized = true; + arg._size = sizeof(__ifunc_arg_t); + arg._hwcap = getauxval(AT_HWCAP); + arg._hwcap2 = getauxval(AT_HWCAP2); + } return reinterpret_cast<ifunc_resolver_t>(resolver_addr)(arg._hwcap | _IFUNC_ARG_HWCAP, &arg); #elif defined(__arm__) typedef ElfW(Addr) (*ifunc_resolver_t)(unsigned long); - static unsigned long hwcap = getauxval(AT_HWCAP); + static unsigned long hwcap; + static bool initialized = false; + if (!initialized) { + initialized = true; + hwcap = getauxval(AT_HWCAP); + } return reinterpret_cast<ifunc_resolver_t>(resolver_addr)(hwcap); #else typedef ElfW(Addr) (*ifunc_resolver_t)(void); diff --git a/libc/bionic/bionic_netlink.cpp b/libc/bionic/bionic_netlink.cpp index f2449dc9a..5d5a02624 100644 --- a/libc/bionic/bionic_netlink.cpp +++ b/libc/bionic/bionic_netlink.cpp @@ -39,8 +39,6 @@ #include "private/ErrnoRestorer.h" NetlinkConnection::NetlinkConnection() { - fd_ = -1; - // The kernel keeps packets under 8KiB (NLMSG_GOODSIZE), // but that's a bit too large to go on the stack. size_ = 8192; @@ -48,8 +46,6 @@ NetlinkConnection::NetlinkConnection() { } NetlinkConnection::~NetlinkConnection() { - ErrnoRestorer errno_restorer; - if (fd_ != -1) close(fd_); delete[] data_; } @@ -59,9 +55,9 @@ bool NetlinkConnection::SendRequest(int type) { if (data_ == nullptr) return false; // Did we open a netlink socket yet? - if (fd_ == -1) { - fd_ = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); - if (fd_ == -1) return false; + if (fd_.get() == -1) { + fd_.reset(socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE)); + if (fd_.get() == -1) return false; } // Construct and send the message. @@ -74,13 +70,13 @@ bool NetlinkConnection::SendRequest(int type) { request.hdr.nlmsg_type = type; request.hdr.nlmsg_len = sizeof(request); request.msg.rtgen_family = AF_UNSPEC; // All families. - return (TEMP_FAILURE_RETRY(send(fd_, &request, sizeof(request), 0)) == sizeof(request)); + return (TEMP_FAILURE_RETRY(send(fd_.get(), &request, sizeof(request), 0)) == sizeof(request)); } bool NetlinkConnection::ReadResponses(void callback(void*, nlmsghdr*), void* context) { // Read through all the responses, handing interesting ones to the callback. ssize_t bytes_read; - while ((bytes_read = TEMP_FAILURE_RETRY(recv(fd_, data_, size_, 0))) > 0) { + while ((bytes_read = TEMP_FAILURE_RETRY(recv(fd_.get(), data_, size_, 0))) > 0) { nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(data_); for (; NLMSG_OK(hdr, static_cast<size_t>(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) { if (hdr->nlmsg_type == NLMSG_DONE) return true; diff --git a/libc/bionic/bionic_netlink.h b/libc/bionic/bionic_netlink.h index a21200e64..fc1bd0fb0 100644 --- a/libc/bionic/bionic_netlink.h +++ b/libc/bionic/bionic_netlink.h @@ -33,6 +33,8 @@ #include <linux/netlink.h> #include <linux/rtnetlink.h> +#include "private/ScopedFd.h" + struct nlmsghdr; class NetlinkConnection { @@ -44,7 +46,7 @@ class NetlinkConnection { bool ReadResponses(void callback(void*, nlmsghdr*), void* context); private: - int fd_; + ScopedFd fd_; char* data_; size_t size_; }; diff --git a/libc/bionic/fchmodat.cpp b/libc/bionic/fchmodat.cpp index c28e15ac7..632d2ac85 100644 --- a/libc/bionic/fchmodat.cpp +++ b/libc/bionic/fchmodat.cpp @@ -32,7 +32,7 @@ #include <errno.h> #include <unistd.h> -#include "private/ErrnoRestorer.h" +#include "private/ScopedFd.h" extern "C" int __fchmodat(int, const char*, mode_t); @@ -47,20 +47,15 @@ int fchmodat(int dirfd, const char* pathname, mode_t mode, int flags) { // at https://sourceware.org/bugzilla/show_bug.cgi?id=14578 // comment #10 - int fd = openat(dirfd, pathname, O_PATH | O_NOFOLLOW | O_CLOEXEC); - if (fd == -1) { - return -1; // returns errno from openat - } + ScopedFd fd(openat(dirfd, pathname, O_PATH | O_NOFOLLOW | O_CLOEXEC)); + if (fd.get() == -1) return -1; // POSIX requires that ENOTSUP be returned when the system // doesn't support setting the mode of a symbolic link. // This is true for all Linux kernels. // We rely on the O_PATH compatibility layer added in the // fchmod() function to get errno correct. - int result = fchmod(fd, mode); - ErrnoRestorer errno_restorer; // don't let close() clobber errno - close(fd); - return result; + return fchmod(fd.get(), mode); } return __fchmodat(dirfd, pathname, mode); diff --git a/libc/bionic/getauxval.cpp b/libc/bionic/getauxval.cpp index c8f867b64..f865f97b4 100644 --- a/libc/bionic/getauxval.cpp +++ b/libc/bionic/getauxval.cpp @@ -36,7 +36,6 @@ // This function needs to be safe to call before TLS is set up, so it can't // access errno or the stack protector. -__attribute__((no_stack_protector)) __LIBC_HIDDEN__ unsigned long __bionic_getauxval(unsigned long type, bool& exists) { for (ElfW(auxv_t)* v = __libc_shared_globals()->auxv; v->a_type != AT_NULL; ++v) { if (v->a_type == type) { diff --git a/libc/bionic/getentropy.cpp b/libc/bionic/getentropy.cpp index 2c6e417b8..9c93e713b 100644 --- a/libc/bionic/getentropy.cpp +++ b/libc/bionic/getentropy.cpp @@ -31,22 +31,20 @@ #include <sys/random.h> #include <unistd.h> +#include "private/ScopedFd.h" + static int getentropy_urandom(void* buffer, size_t buffer_size, int saved_errno) { - int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_NOFOLLOW | O_CLOEXEC, 0)); - if (fd == -1) return -1; + ScopedFd fd(TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_NOFOLLOW | O_CLOEXEC, 0))); + if (fd.get() == -1) return -1; size_t collected = 0; while (collected < buffer_size) { - ssize_t count = TEMP_FAILURE_RETRY(read(fd, static_cast<char*>(buffer) + collected, + ssize_t count = TEMP_FAILURE_RETRY(read(fd.get(), static_cast<char*>(buffer) + collected, buffer_size - collected)); - if (count == -1) { - close(fd); - return -1; - } + if (count == -1) return -1; collected += count; } - close(fd); errno = saved_errno; return 0; } diff --git a/libc/bionic/grp_pwd_file.cpp b/libc/bionic/grp_pwd_file.cpp index e13604e68..81cf8936d 100644 --- a/libc/bionic/grp_pwd_file.cpp +++ b/libc/bionic/grp_pwd_file.cpp @@ -37,6 +37,7 @@ #include <async_safe/log.h> #include "private/ErrnoRestorer.h" +#include "private/ScopedFd.h" // This file mmap's /*/etc/passwd and /*/etc/group in order to return their contents without any // allocations. Note that these files and the strings contained within them are explicitly not @@ -230,19 +231,16 @@ bool MmapFile::GetFile(const char** start, const char** end) { } bool MmapFile::DoMmap() { - int fd = open(filename_, O_CLOEXEC | O_NOFOLLOW | O_RDONLY); + ScopedFd fd(open(filename_, O_CLOEXEC | O_NOFOLLOW | O_RDONLY)); struct stat fd_stat; - if (fstat(fd, &fd_stat) == -1) { - close(fd); + if (fstat(fd.get(), &fd_stat) == -1) { return false; } auto mmap_size = fd_stat.st_size; - void* map_result = mmap(nullptr, mmap_size, PROT_READ, MAP_SHARED, fd, 0); - close(fd); - + void* map_result = mmap(nullptr, mmap_size, PROT_READ, MAP_SHARED, fd.get(), 0); if (map_result == MAP_FAILED) { return false; } diff --git a/libc/bionic/jemalloc.h b/libc/bionic/jemalloc.h index ef77c9c99..4ce51c0a8 100644 --- a/libc/bionic/jemalloc.h +++ b/libc/bionic/jemalloc.h @@ -29,7 +29,7 @@ __BEGIN_DECLS void* je_aligned_alloc_wrapper(size_t, size_t); -int je_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*); +int je_malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*); int je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) __attribute__((nothrow)); struct mallinfo je_mallinfo(); void je_malloc_disable(); diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp index 7d0445784..ef488eecc 100644 --- a/libc/bionic/jemalloc_wrapper.cpp +++ b/libc/bionic/jemalloc_wrapper.cpp @@ -140,30 +140,32 @@ int je_malloc_info(int options, FILE* fp) { return -1; } - MallocXmlElem root(fp, "malloc", "version=\"jemalloc-1\""); + fflush(fp); + int fd = fileno(fp); + MallocXmlElem root(fd, "malloc", "version=\"jemalloc-1\""); // Dump all of the large allocations in the arenas. for (size_t i = 0; i < je_mallinfo_narenas(); i++) { struct mallinfo mi = je_mallinfo_arena_info(i); if (mi.hblkhd != 0) { - MallocXmlElem arena_elem(fp, "heap", "nr=\"%d\"", i); + MallocXmlElem arena_elem(fd, "heap", "nr=\"%d\"", i); { - MallocXmlElem(fp, "allocated-large").Contents("%zu", mi.ordblks); - MallocXmlElem(fp, "allocated-huge").Contents("%zu", mi.uordblks); - MallocXmlElem(fp, "allocated-bins").Contents("%zu", mi.fsmblks); + MallocXmlElem(fd, "allocated-large").Contents("%zu", mi.ordblks); + MallocXmlElem(fd, "allocated-huge").Contents("%zu", mi.uordblks); + MallocXmlElem(fd, "allocated-bins").Contents("%zu", mi.fsmblks); size_t total = 0; for (size_t j = 0; j < je_mallinfo_nbins(); j++) { struct mallinfo mi = je_mallinfo_bin_info(i, j); if (mi.ordblks != 0) { - MallocXmlElem bin_elem(fp, "bin", "nr=\"%d\"", j); - MallocXmlElem(fp, "allocated").Contents("%zu", mi.ordblks); - MallocXmlElem(fp, "nmalloc").Contents("%zu", mi.uordblks); - MallocXmlElem(fp, "ndalloc").Contents("%zu", mi.fordblks); + MallocXmlElem bin_elem(fd, "bin", "nr=\"%d\"", j); + MallocXmlElem(fd, "allocated").Contents("%zu", mi.ordblks); + MallocXmlElem(fd, "nmalloc").Contents("%zu", mi.uordblks); + MallocXmlElem(fd, "ndalloc").Contents("%zu", mi.fordblks); total += mi.ordblks; } } - MallocXmlElem(fp, "bins-total").Contents("%zu", total); + MallocXmlElem(fd, "bins-total").Contents("%zu", total); } } } diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp index 0b740232a..28c0b0c95 100644 --- a/libc/bionic/libc_init_static.cpp +++ b/libc/bionic/libc_init_static.cpp @@ -231,6 +231,9 @@ extern "C" void android_set_application_target_sdk_version(int target) { g_target_sdk_version = target; } +// This function is called in the dynamic linker before ifunc resolvers have run, so this file is +// compiled with -ffreestanding to avoid implicit string.h function calls. (It shouldn't strictly +// be necessary, though.) __LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals() { static libc_shared_globals globals; return &globals; diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 96e614048..a0da3dbff 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -215,9 +215,9 @@ extern "C" int malloc_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) { auto dispatch_table = GetDispatchTable(); if (__predict_false(dispatch_table != nullptr)) { - return dispatch_table->iterate(base, size, callback, arg); + return dispatch_table->malloc_iterate(base, size, callback, arg); } - return Malloc(iterate)(base, size, callback, arg); + return Malloc(malloc_iterate)(base, size, callback, arg); } // Disable calls to malloc so malloc_iterate gets a consistent view of @@ -247,9 +247,10 @@ extern "C" ssize_t malloc_backtrace(void*, uintptr_t*, size_t) { #if __has_feature(hwaddress_sanitizer) // FIXME: implement these in HWASan allocator. -extern "C" int __sanitizer_iterate(uintptr_t base __unused, size_t size __unused, - void (*callback)(uintptr_t base, size_t size, void* arg) __unused, - void* arg __unused) { +extern "C" int __sanitizer_malloc_iterate(uintptr_t base __unused, size_t size __unused, + void (*callback)(uintptr_t base, size_t size, void* arg) + __unused, + void* arg __unused) { return 0; } diff --git a/libc/bionic/malloc_common.h b/libc/bionic/malloc_common.h index 2176e634d..89dccc31a 100644 --- a/libc/bionic/malloc_common.h +++ b/libc/bionic/malloc_common.h @@ -42,9 +42,9 @@ __BEGIN_DECLS // FIXME: implement these in HWASan allocator. -int __sanitizer_iterate(uintptr_t base, size_t size, - void (*callback)(uintptr_t base, size_t size, void* arg), - void* arg); +int __sanitizer_malloc_iterate(uintptr_t base, size_t size, + void (*callback)(uintptr_t base, size_t size, void* arg), + void* arg); void __sanitizer_malloc_disable(); void __sanitizer_malloc_enable(); int __sanitizer_malloc_info(int options, FILE* fp); diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp index 9ad79a0d0..0ac3f62e6 100644 --- a/libc/bionic/malloc_common_dynamic.cpp +++ b/libc/bionic/malloc_common_dynamic.cpp @@ -95,7 +95,7 @@ static constexpr MallocDispatch __libc_malloc_default_dispatch #if defined(HAVE_DEPRECATED_MALLOC_FUNCS) Malloc(valloc), #endif - Malloc(iterate), + Malloc(malloc_iterate), Malloc(malloc_disable), Malloc(malloc_enable), Malloc(mallopt), @@ -184,7 +184,8 @@ static bool InitMallocFunctions(void* impl_handler, MallocDispatch* table, const if (!InitMallocFunction<MallocRealloc>(impl_handler, &table->realloc, prefix, "realloc")) { return false; } - if (!InitMallocFunction<MallocIterate>(impl_handler, &table->iterate, prefix, "iterate")) { + if (!InitMallocFunction<MallocIterate>(impl_handler, &table->malloc_iterate, prefix, + "malloc_iterate")) { return false; } if (!InitMallocFunction<MallocMallocDisable>(impl_handler, &table->malloc_disable, prefix, diff --git a/libc/bionic/malloc_heapprofd.cpp b/libc/bionic/malloc_heapprofd.cpp index 62249fb1d..586022200 100644 --- a/libc/bionic/malloc_heapprofd.cpp +++ b/libc/bionic/malloc_heapprofd.cpp @@ -104,7 +104,7 @@ static constexpr MallocDispatch __heapprofd_init_dispatch #if defined(HAVE_DEPRECATED_MALLOC_FUNCS) Malloc(valloc), #endif - Malloc(iterate), + Malloc(malloc_iterate), Malloc(malloc_disable), Malloc(malloc_enable), Malloc(mallopt), diff --git a/libc/bionic/malloc_limit.cpp b/libc/bionic/malloc_limit.cpp index 6a67cae95..d8c0ebe54 100644 --- a/libc/bionic/malloc_limit.cpp +++ b/libc/bionic/malloc_limit.cpp @@ -350,9 +350,9 @@ static struct mallinfo LimitMallinfo() { static int LimitIterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_t, void*), void* arg) { auto dispatch_table = GetDefaultDispatchTable(); if (__predict_false(dispatch_table != nullptr)) { - return dispatch_table->iterate(base, size, callback, arg); + return dispatch_table->malloc_iterate(base, size, callback, arg); } - return Malloc(iterate)(base, size, callback, arg); + return Malloc(malloc_iterate)(base, size, callback, arg); } static void LimitMallocDisable() { diff --git a/libc/bionic/net_if.cpp b/libc/bionic/net_if.cpp index db9c9ea22..ad53364c9 100644 --- a/libc/bionic/net_if.cpp +++ b/libc/bionic/net_if.cpp @@ -40,37 +40,27 @@ #include <sys/socket.h> #include <unistd.h> -#include "private/ErrnoRestorer.h" +#include "private/ScopedFd.h" #include "bionic_netlink.h" char* if_indextoname(unsigned ifindex, char* ifname) { - int s = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0); - if (s == -1) return nullptr; + ScopedFd s(socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0)); + if (s.get() == -1) return nullptr; - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_ifindex = ifindex; - - int rc = ioctl(s, SIOCGIFNAME, &ifr); - ErrnoRestorer errno_restorer; - close(s); - return (rc == -1) ? nullptr : strncpy(ifname, ifr.ifr_name, IFNAMSIZ); + ifreq ifr = {.ifr_ifindex = static_cast<int>(ifindex)}; + return (ioctl(s.get(), SIOCGIFNAME, &ifr) == -1) ? nullptr + : strncpy(ifname, ifr.ifr_name, IFNAMSIZ); } unsigned if_nametoindex(const char* ifname) { - int s = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0); - if (s == -1) return 0; + ScopedFd s(socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0)); + if (s.get() == -1) return 0; - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); + ifreq ifr = {}; strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ifr.ifr_name[IFNAMSIZ - 1] = 0; - - int rc = ioctl(s, SIOCGIFINDEX, &ifr); - ErrnoRestorer errno_restorer; - close(s); - return (rc == -1) ? 0 : ifr.ifr_ifindex; + return (ioctl(s.get(), SIOCGIFINDEX, &ifr) == -1) ? 0 : ifr.ifr_ifindex; } struct if_list { diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp index 1dc10667b..03af2d94a 100644 --- a/libc/bionic/pthread_create.cpp +++ b/libc/bionic/pthread_create.cpp @@ -54,31 +54,12 @@ void __init_user_desc(struct user_desc*, bool, void*); #endif -// This code is used both by each new pthread and the code that initializes the main thread. -__attribute__((no_stack_protector)) -void __init_tcb(bionic_tcb* tcb, pthread_internal_t* thread) { -#ifdef TLS_SLOT_SELF - // On x86, slot 0 must point to itself so code can read the thread pointer by - // loading %fs:0 or %gs:0. - tcb->tls_slot(TLS_SLOT_SELF) = &tcb->tls_slot(TLS_SLOT_SELF); -#endif - tcb->tls_slot(TLS_SLOT_THREAD_ID) = thread; -} - __attribute__((no_stack_protector)) void __init_tcb_stack_guard(bionic_tcb* tcb) { // GCC looks in the TLS for the stack guard on x86, so copy it there from our global. tcb->tls_slot(TLS_SLOT_STACK_GUARD) = reinterpret_cast<void*>(__stack_chk_guard); } -__attribute__((no_stack_protector)) -void __init_tcb_dtv(bionic_tcb* tcb) { - // Initialize the DTV slot to a statically-allocated empty DTV. The first - // access to a dynamic TLS variable allocates a new DTV. - static const TlsDtv zero_dtv = {}; - __set_tcb_dtv(tcb, const_cast<TlsDtv*>(&zero_dtv)); -} - void __init_bionic_tls_ptrs(bionic_tcb* tcb, bionic_tls* tls) { tcb->thread()->bionic_tls = tls; tcb->tls_slot(TLS_SLOT_BIONIC_TLS) = tls; diff --git a/libc/bionic/scudo.h b/libc/bionic/scudo.h index d9933c4d0..a80d75418 100644 --- a/libc/bionic/scudo.h +++ b/libc/bionic/scudo.h @@ -52,7 +52,7 @@ void* scudo_pvalloc(size_t); void* scudo_valloc(size_t); #endif -int scudo_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*); +int scudo_malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*); void scudo_malloc_disable(); void scudo_malloc_enable(); diff --git a/libc/bionic/scudo_wrapper.cpp b/libc/bionic/scudo_wrapper.cpp index e17f20ba5..debd8d996 100644 --- a/libc/bionic/scudo_wrapper.cpp +++ b/libc/bionic/scudo_wrapper.cpp @@ -48,7 +48,7 @@ int scudo_malloc_info(int /*options*/, FILE* /*fp*/) { return -1; } -int scudo_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) { +int scudo_malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) { return 0; } diff --git a/libc/bionic/system_property_api.cpp b/libc/bionic/system_property_api.cpp index 051bc4c4f..a641f12a8 100644 --- a/libc/bionic/system_property_api.cpp +++ b/libc/bionic/system_property_api.cpp @@ -100,7 +100,13 @@ int __system_property_add(const char* name, unsigned int namelen, const char* va __BIONIC_WEAK_FOR_NATIVE_BRIDGE uint32_t __system_property_serial(const prop_info* pi) { - return system_properties.Serial(pi); + // N.B. a previous version of this function was much heavier-weight + // and enforced acquire semantics, so give our load here acquire + // semantics just in case somebody depends on + // __system_property_serial enforcing memory order, e.g., in case + // someone spins on the result of this function changing before + // loading some value. + return atomic_load_explicit(&pi->serial, memory_order_acquire); } __BIONIC_WEAK_FOR_NATIVE_BRIDGE diff --git a/libc/bionic/system_property_set.cpp b/libc/bionic/system_property_set.cpp index c508db162..e981a58d9 100644 --- a/libc/bionic/system_property_set.cpp +++ b/libc/bionic/system_property_set.cpp @@ -46,6 +46,7 @@ #include "private/bionic_defs.h" #include "private/bionic_macros.h" +#include "private/ScopedFd.h" static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME; static const char* kServiceVersionPropertyName = "ro.property_service.version"; @@ -53,8 +54,8 @@ static const char* kServiceVersionPropertyName = "ro.property_service.version"; class PropertyServiceConnection { public: PropertyServiceConnection() : last_error_(0) { - socket_ = ::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (socket_ == -1) { + socket_.reset(::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0)); + if (socket_.get() == -1) { last_error_ = errno; return; } @@ -66,15 +67,15 @@ class PropertyServiceConnection { addr.sun_family = AF_LOCAL; socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1; - if (TEMP_FAILURE_RETRY(connect(socket_, reinterpret_cast<sockaddr*>(&addr), alen)) == -1) { + if (TEMP_FAILURE_RETRY(connect(socket_.get(), + reinterpret_cast<sockaddr*>(&addr), alen)) == -1) { last_error_ = errno; - close(socket_); - socket_ = -1; + socket_.reset(); } } bool IsValid() { - return socket_ != -1; + return socket_.get() != -1; } int GetLastError() { @@ -82,18 +83,12 @@ class PropertyServiceConnection { } bool RecvInt32(int32_t* value) { - int result = TEMP_FAILURE_RETRY(recv(socket_, value, sizeof(*value), MSG_WAITALL)); + int result = TEMP_FAILURE_RETRY(recv(socket_.get(), value, sizeof(*value), MSG_WAITALL)); return CheckSendRecvResult(result, sizeof(*value)); } int socket() { - return socket_; - } - - ~PropertyServiceConnection() { - if (socket_ != -1) { - close(socket_); - } + return socket_.get(); } private: @@ -109,7 +104,7 @@ class PropertyServiceConnection { return last_error_ == 0; } - int socket_; + ScopedFd socket_; int last_error_; friend class SocketWriter; diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c index 4e1aa61d5..d0c11d2b0 100644 --- a/libc/dns/net/getaddrinfo.c +++ b/libc/dns/net/getaddrinfo.c @@ -470,7 +470,7 @@ android_getaddrinfo_proxy( break; } - struct addrinfo* ai = calloc(1, sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); + ai = calloc(1, sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); if (ai == NULL) { break; } diff --git a/libc/include/bits/sys_statvfs_inlines.h b/libc/include/bits/sys_statvfs_inlines.h index fd4578cd5..991fac716 100644 --- a/libc/include/bits/sys_statvfs_inlines.h +++ b/libc/include/bits/sys_statvfs_inlines.h @@ -38,20 +38,20 @@ __BEGIN_DECLS #if defined(__BIONIC_NEED_STATVFS_INLINES) -static __inline void __bionic_statfs_to_statvfs(const struct statfs* __in, - struct statvfs* __out) { - __out->f_bsize = __in->f_bsize; - __out->f_frsize = __in->f_frsize; - __out->f_blocks = __in->f_blocks; - __out->f_bfree = __in->f_bfree; - __out->f_bavail = __in->f_bavail; - __out->f_files = __in->f_files; - __out->f_ffree = __in->f_ffree; - __out->f_favail = __in->f_ffree; - __out->f_fsid = __in->f_fsid.__val[0] | - __BIONIC_CAST(static_cast, uint64_t, __in->f_fsid.__val[1]) << 32; - __out->f_flag = __in->f_flags; - __out->f_namemax = __in->f_namelen; +static __inline void __bionic_statfs_to_statvfs(const struct statfs* __src, + struct statvfs* __dst) { + __dst->f_bsize = __src->f_bsize; + __dst->f_frsize = __src->f_frsize; + __dst->f_blocks = __src->f_blocks; + __dst->f_bfree = __src->f_bfree; + __dst->f_bavail = __src->f_bavail; + __dst->f_files = __src->f_files; + __dst->f_ffree = __src->f_ffree; + __dst->f_favail = __src->f_ffree; + __dst->f_fsid = __src->f_fsid.__val[0] | + __BIONIC_CAST(static_cast, uint64_t, __src->f_fsid.__val[1]) << 32; + __dst->f_flag = __src->f_flags; + __dst->f_namemax = __src->f_namelen; } __BIONIC_SYS_STATVFS_INLINE int statvfs(const char* __path, diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h index 1c5d64c19..c45c91ff4 100644 --- a/libc/include/fcntl.h +++ b/libc/include/fcntl.h @@ -26,9 +26,14 @@ * SUCH DAMAGE. */ -#ifndef _FCNTL_H +#pragma once #define _FCNTL_H +/** + * @file fcntl.h + * @brief File control operations. + */ + #include <sys/cdefs.h> #include <sys/types.h> #include <linux/fadvise.h> @@ -48,47 +53,180 @@ __BEGIN_DECLS #ifdef __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 #endif +/** Flag for open(). */ #define O_ASYNC FASYNC +/** Flag for open(). */ #define O_RSYNC O_SYNC #if __ANDROID_API__ >= __ANDROID_API_L__ +/** Flag for splice(). */ #define SPLICE_F_MOVE 1 +/** Flag for splice(). */ #define SPLICE_F_NONBLOCK 2 +/** Flag for splice(). */ #define SPLICE_F_MORE 4 +/** Flag for splice(). */ #define SPLICE_F_GIFT 8 #endif #if __ANDROID_API__ >= __ANDROID_API_O__ +/** Flag for sync_file_range(). */ #define SYNC_FILE_RANGE_WAIT_BEFORE 1 +/** Flag for sync_file_range(). */ #define SYNC_FILE_RANGE_WRITE 2 +/** Flag for sync_file_range(). */ #define SYNC_FILE_RANGE_WAIT_AFTER 4 #endif +/** + * [creat(2)](http://man7.org/linux/man-pages/man2/creat.2.html) + * creates a file. + * + * Returns a new file descriptor on success and returns -1 and sets `errno` on + * failure. + */ int creat(const char* __path, mode_t __mode); +/** See creat(). */ int creat64(const char* __path, mode_t __mode) __INTRODUCED_IN(21); + +/** + * [openat(2)](http://man7.org/linux/man-pages/man2/openat.2.html) + * opens (and possibly creates) a file. + * + * Returns a new file descriptor on success and returns -1 and sets `errno` on + * failure. + */ int openat(int __dir_fd, const char* __path, int __flags, ...); +/** See openat(). */ int openat64(int __dir_fd, const char* __path, int __flags, ...) __INTRODUCED_IN(21); + +/** + * [open(2)](http://man7.org/linux/man-pages/man2/open.2.html) + * opens (and possibly creates) a file. + * + * Returns a new file descriptor on success and returns -1 and sets `errno` on + * failure. + */ int open(const char* __path, int __flags, ...); +/** See open(). */ int open64(const char* __path, int __flags, ...) __INTRODUCED_IN(21); + +/** + * [splice(2)](http://man7.org/linux/man-pages/man2/splice.2.html) + * splices data to/from a pipe. + * + * Valid flags are `SPLICE_F_MOVE`, `SPLICE_F_NONBLOCK`, `SPLICE_F_MORE`, and + * `SPLICE_F_GIFT`. + * + * Returns the number of bytes spliced on success and returns -1 and sets + * `errno` on failure. + * + * Available since API level 21. + */ ssize_t splice(int __in_fd, off64_t* __in_offset, int __out_fd, off64_t* __out_offset, size_t __length, unsigned int __flags) __INTRODUCED_IN(21); + +/** + * [tee(2)](http://man7.org/linux/man-pages/man2/tee.2.html) + * duplicates data from one pipe to another. + * + * Valid flags are `SPLICE_F_MOVE`, `SPLICE_F_NONBLOCK`, `SPLICE_F_MORE`, and + * `SPLICE_F_GIFT`. + * + * Returns the number of bytes duplicated on success and returns -1 and sets + * `errno` on failure. + * + * Available since API level 21. + */ ssize_t tee(int __in_fd, int __out_fd, size_t __length, unsigned int __flags) __INTRODUCED_IN(21); + +/** + * [vmsplice(2)](http://man7.org/linux/man-pages/man2/vmsplice.2.html) + * splices data to/from a pipe. + * + * Valid flags are `SPLICE_F_MOVE`, `SPLICE_F_NONBLOCK`, `SPLICE_F_MORE`, and + * `SPLICE_F_GIFT`. + * + * Returns the number of bytes spliced on success and returns -1 and sets + * `errno` on failure. + * + * Available since API level 21. + */ ssize_t vmsplice(int __fd, const struct iovec* __iov, size_t __count, unsigned int __flags) __INTRODUCED_IN(21); +/** + * [fallocate(2)](http://man7.org/linux/man-pages/man2/fallocate.2.html) + * is a Linux-specific extension of posix_fallocate(). + * + * Valid flags are `FALLOC_FL_KEEP_SIZE`, `FALLOC_FL_PUNCH_HOLE`, + * `FALLOC_FL_NO_HIDE_STALE`, `FALLOC_FL_COLLAPSE_RANGE`, + * `FALLOC_FL_ZERO_RANGE`, `FALLOC_FL_INSERT_RANGE`, and + * `FALLOC_FL_UNSHARE_RANGE`. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + * + * Available since API level 21. + */ int fallocate(int __fd, int __mode, off_t __offset, off_t __length) __RENAME_IF_FILE_OFFSET64(fallocate64) __INTRODUCED_IN(21); +/** See fallocate(). */ int fallocate64(int __fd, int __mode, off64_t __offset, off64_t __length) __INTRODUCED_IN(21); + +/** + * [posix_fadvise(2)](http://man7.org/linux/man-pages/man2/posix_fadvise.2.html) + * declares an expected access pattern for file data. + * + * Valid flags are `POSIX_FADV_NORMAL`, `POSIX_FADV_RANDOM`, + * `POSIX_FADV_SEQUENTIAL`, `POSIX_FADV_WILLNEED`, `POSIX_FADV_DONTNEED`, + * and `POSIX_FADV_NOREUSE`. + * + * Returns 0 on success and returns an error number on failure. + * + * Available since API level 21. + */ int posix_fadvise(int __fd, off_t __offset, off_t __length, int __advice) __RENAME_IF_FILE_OFFSET64(posix_fadvise64) __INTRODUCED_IN(21); +/** See posix_fadvise(). */ int posix_fadvise64(int __fd, off64_t __offset, off64_t __length, int __advice) __INTRODUCED_IN(21); + +/** + * [posix_fallocate(2)](http://man7.org/linux/man-pages/man2/posix_fallocate.2.html) + * allocates file space. + * + * Returns 0 on success and returns an error number on failure. + * + * Available since API level 21. + */ int posix_fallocate(int __fd, off_t __offset, off_t __length) __RENAME_IF_FILE_OFFSET64(posix_fallocate64) __INTRODUCED_IN(21); +/** See posix_fallocate(). */ int posix_fallocate64(int __fd, off64_t __offset, off64_t __length) __INTRODUCED_IN(21); #if defined(__USE_GNU) -ssize_t readahead(int __fd, off64_t __offset, size_t __length) __INTRODUCED_IN(16); + +/** + * [readahead(2)](http://man7.org/linux/man-pages/man2/readahead.2.html) + * initiates readahead for the given file. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + */ +ssize_t readahead(int __fd, off64_t __offset, size_t __length); + +/** + * [sync_file_range(2)](http://man7.org/linux/man-pages/man2/sync_file_range.2.html) + * syncs part of a file with disk. + * + * Valid flags are `SYNC_FILE_RANGE_WAIT_BEFORE`, `SYNC_FILE_RANGE_WRITE`, and + * `SYNC_FILE_RANGE_WAIT_AFTER`. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + */ int sync_file_range(int __fd, off64_t __offset, off64_t __length, unsigned int __flags) __INTRODUCED_IN(26); + #endif #if defined(__BIONIC_INCLUDE_FORTIFY_HEADERS) @@ -96,5 +234,3 @@ int sync_file_range(int __fd, off64_t __offset, off64_t __length, unsigned int _ #endif __END_DECLS - -#endif diff --git a/libc/include/search.h b/libc/include/search.h index 97fdedaeb..7a75404c9 100644 --- a/libc/include/search.h +++ b/libc/include/search.h @@ -6,30 +6,56 @@ * $FreeBSD: release/9.0.0/include/search.h 105250 2002-10-16 14:29:23Z robert $ */ -#ifndef _SEARCH_H_ -#define _SEARCH_H_ +#pragma once + +/** + * @file search.h + * @brief Queues, hash tables, trees, and linear array searches. + */ #include <sys/cdefs.h> #include <sys/types.h> +/** See hsearch()/hsearch_r(). */ typedef enum { FIND, ENTER } ACTION; +/** See hsearch()/hsearch_r(). */ typedef struct entry { + /** The string key. */ char* key; + /** The associated data. */ void* data; } ENTRY; +/** + * Constants given to the twalk() visitor. + * Note that the constant names are misleading. + */ typedef enum { + /** + * If this is the first visit to a non-leaf node. + * Use this for *preorder* traversal. + */ preorder, + /** + * If this is the second visit to a non-leaf node. + * Use this for *inorder* traversal. + */ postorder, + /** + * If this is the third visit to a non-leaf node. + * Use this for *postorder* traversal. + */ endorder, + /** If this is the first and only visit to a leaf node. */ leaf } VISIT; #if defined(__USE_BSD) || defined(__USE_GNU) +/** The hash table type for hcreate_r()/hdestroy_r()/hsearch_r(). */ struct hsearch_data { struct __hsearch* __hsearch; }; @@ -37,30 +63,157 @@ struct hsearch_data { __BEGIN_DECLS +/** + * [insque(3)](http://man7.org/linux/man-pages/man3/insque.3.html) inserts + * an item in a queue (an intrusive doubly-linked list). + * + * Available since API level 21. + */ void insque(void* __element, void* __previous) __INTRODUCED_IN(21); + +/** + * [remque(3)](http://man7.org/linux/man-pages/man3/remque.3.html) removes + * an item from a queue (an intrusive doubly-linked list). + * + * Available since API level 21. + */ void remque(void* __element) __INTRODUCED_IN(21); -int hcreate(size_t) __INTRODUCED_IN(28); +/** + * [hcreate(3)](http://man7.org/linux/man-pages/man3/hcreate.3.html) + * initializes the global hash table, with space for at least `__n` elements. + * + * See hcreate_r() if you need more than one hash table. + * + * Returns *non-zero* on success and returns 0 and sets `errno` on failure. + * + * Available since API level 28. + */ +int hcreate(size_t __n) __INTRODUCED_IN(28); + +/** + * [hdestroy(3)](http://man7.org/linux/man-pages/man3/hdestroy.3.html) destroys + * the global hash table. + * + * See hdestroy_r() if you need more than one hash table. + * + * Available since API level 28. + */ void hdestroy(void) __INTRODUCED_IN(28); -ENTRY* hsearch(ENTRY, ACTION) __INTRODUCED_IN(28); + +/** + * [hsearch(3)](http://man7.org/linux/man-pages/man3/hsearch.3.html) finds or + * inserts `__entry` in the global hash table, based on `__action`. + * + * See hsearch_r() if you need more than one hash table. + * + * Returns a pointer to the entry on success, and returns NULL and sets + * `errno` on failure. + * + * Available since API level 28. + */ +ENTRY* hsearch(ENTRY __entry, ACTION __action) __INTRODUCED_IN(28); #if defined(__USE_BSD) || defined(__USE_GNU) -int hcreate_r(size_t, struct hsearch_data*) __INTRODUCED_IN(28); -void hdestroy_r(struct hsearch_data*) __INTRODUCED_IN(28); -int hsearch_r(ENTRY, ACTION, ENTRY**, struct hsearch_data*) __INTRODUCED_IN(28); -#endif -void* lfind(const void* __key, const void* __base, size_t* __count, size_t __size, int (*__comparator)(const void*, const void*)) - __INTRODUCED_IN(21); -void* lsearch(const void* __key, void* __base, size_t* __count, size_t __size, int (*__comparator)(const void*, const void*)) - __INTRODUCED_IN(21); +/** + * [hcreate_r(3)](http://man7.org/linux/man-pages/man3/hcreate_r.3.html) + * initializes a hash table `__table` with space for at least `__n` elements. + * + * Returns *non-zero* on success and returns 0 and sets `errno` on failure. + * + * Available since API level 28. + */ +int hcreate_r(size_t __n, struct hsearch_data* __table) __INTRODUCED_IN(28); -void* tdelete(const void* __key, void** __root_ptr, int (*__comparator)(const void*, const void*)) __INTRODUCED_IN(16); -void tdestroy(void* __root, void (*__free_fn)(void*)) __INTRODUCED_IN(16); -void* tfind(const void* __key, void* const* __root_ptr, int (*__comparator)(const void*, const void*)) __INTRODUCED_IN(16); -void* tsearch(const void* __key, void** __root_ptr, int (*__comparator)(const void*, const void*)) __INTRODUCED_IN(16); -void twalk(const void* __root, void (*__visitor)(const void*, VISIT, int)) __INTRODUCED_IN(21); +/** + * [hdestroy_r(3)](http://man7.org/linux/man-pages/man3/hdestroy_r.3.html) destroys + * the hash table `__table`. + * + * Available since API level 28. + */ +void hdestroy_r(struct hsearch_data* __table) __INTRODUCED_IN(28); -__END_DECLS +/** + * [hsearch_r(3)](http://man7.org/linux/man-pages/man3/hsearch_r.3.html) finds or + * inserts `__entry` in the hash table `__table`, based on `__action`. + * + * Returns *non-zero* on success and returns 0 and sets `errno` on failure. + * A pointer to the entry is returned in `*__result`. + * + * Available since API level 28. + */ +int hsearch_r(ENTRY __entry, ACTION __action, ENTRY** __result, struct hsearch_data* __table) __INTRODUCED_IN(28); #endif + +/** + * [lfind(3)](http://man7.org/linux/man-pages/man3/lfind.3.html) brute-force + * searches the unsorted array `__array` (of `__count` items each of size `__size`) + * for `__key`, using `__comparator`. + * + * See bsearch() if you have a sorted array. + * + * Returns a pointer to the matching element on success, or NULL on failure. + * + * Available since API level 21. + */ +void* lfind(const void* __key, const void* __array, size_t* __count, size_t __size, int (*__comparator)(const void*, const void*)) __INTRODUCED_IN(21); + +/** + * [lsearch(3)](http://man7.org/linux/man-pages/man3/lsearch.3.html) brute-force + * searches the unsorted array `__array` (of `__count` items each of size `__size`) + * for `__key`, using `__comparator`. + * + * Unlike lfind(), on failure lsearch() will *insert* `__key` at the end of + * `__array` and increment `*__count`. + * + * Returns a pointer to the matching element on success, or to the newly-added + * element on failure. + * + * Available since API level 21. + */ +void* lsearch(const void* __key, void* __array, size_t* __count, size_t __size, int (*__comparator)(const void*, const void*)) __INTRODUCED_IN(21); + +/** + * [tdelete(3)](http://man7.org/linux/man-pages/man3/tdelete.3.html) searches + * for and removes an element in the tree `*__root_ptr`. The search is performed + * using `__comparator`. + * + * Returns a pointer to the parent of the deleted node, or NULL on failure. + */ +void* tdelete(const void* __key, void** __root_ptr, int (*__comparator)(const void*, const void*)); + +/** + * [tdestroy(3)](http://man7.org/linux/man-pages/man3/tdestroy.3.html) destroys + * the hash table `__root` using `__free_fn` on each node. + */ +void tdestroy(void* __root, void (*__free_fn)(void*)); + +/** + * [tfind(3)](http://man7.org/linux/man-pages/man3/tfind.3.html) searches + * for an element in the tree `*__root_ptr`. The search is performed using + * `__comparator`. + * + * Returns a pointer to the matching node, or NULL on failure. + */ +void* tfind(const void* __key, void* const* __root_ptr, int (*__comparator)(const void*, const void*)); + +/** + * [tsearch(3)](http://man7.org/linux/man-pages/man3/tsearch.3.html) searches + * for an element in the tree `*__root_ptr`. The search is performed using + * `__comparator`. + * + * Unlike tfind(), on failure tsearch() will *insert* `__key` into the tree. + * + * Returns a pointer to the matching node, or to the newly-added node. + */ +void* tsearch(const void* __key, void** __root_ptr, int (*__comparator)(const void*, const void*)); + +/** + * [twalk(3)](http://man7.org/linux/man-pages/man3/twalk.3.html) calls + * `__visitor` on every node in the tree. + */ +void twalk(const void* __root, void (*__visitor)(const void*, VISIT, int)); + +__END_DECLS diff --git a/libc/include/sys/xattr.h b/libc/include/sys/xattr.h index d15b3fce9..dc58026eb 100644 --- a/libc/include/sys/xattr.h +++ b/libc/include/sys/xattr.h @@ -26,8 +26,12 @@ * SUCH DAMAGE. */ -#ifndef _SYS_XATTR_H_ -#define _SYS_XATTR_H_ +#pragma once + +/** + * @file sys/xattr.h + * @brief Extended attribute functions. + */ #include <linux/xattr.h> #include <sys/cdefs.h> @@ -35,25 +39,120 @@ __BEGIN_DECLS -int fsetxattr(int __fd, const char* __name, const void* __value, size_t __size, int __flags) - __INTRODUCED_IN(16); -int setxattr(const char* __path, const char* __name, const void* __value, size_t __size, int __flags) - __INTRODUCED_IN(16); -int lsetxattr(const char* __path, const char* __name, const void* __value, size_t __size, int __flags) - __INTRODUCED_IN(16); +/** + * [fsetxattr(2)](http://man7.org/linux/man-pages/man2/fsetxattr.2.html) + * sets an extended attribute on the file referred to by the given file + * descriptor. + * + * Valid flags are `XATTR_CREATE` and `XATTR_REPLACE`. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + */ +int fsetxattr(int __fd, const char* __name, const void* __value, size_t __size, int __flags); -ssize_t fgetxattr(int __fd, const char* __name, void* __value, size_t __size) __INTRODUCED_IN(16); -ssize_t getxattr(const char* __path, const char* __name, void* __value, size_t __size) __INTRODUCED_IN(16); -ssize_t lgetxattr(const char* __path, const char* __name, void* __value, size_t __size) __INTRODUCED_IN(16); +/** + * [setxattr(2)](http://man7.org/linux/man-pages/man2/setxattr.2.html) + * sets an extended attribute on the file referred to by the given path. + * + * Valid flags are `XATTR_CREATE` and `XATTR_REPLACE`. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + */ +int setxattr(const char* __path, const char* __name, const void* __value, size_t __size, int __flags); -ssize_t listxattr(const char* __path, char* __list, size_t __size) __INTRODUCED_IN(16); -ssize_t llistxattr(const char* __path, char* __list, size_t __size) __INTRODUCED_IN(16); -ssize_t flistxattr(int __fd, char* __list, size_t __size) __INTRODUCED_IN(16); +/** + * [lsetxattr(2)](http://man7.org/linux/man-pages/man2/lsetxattr.2.html) + * sets an extended attribute on the file referred to by the given path, which + * is the link itself rather than its target in the case of a symbolic link. + * + * Valid flags are `XATTR_CREATE` and `XATTR_REPLACE`. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + */ +int lsetxattr(const char* __path, const char* __name, const void* __value, size_t __size, int __flags); -int removexattr(const char* __path, const char* __name) __INTRODUCED_IN(16); -int lremovexattr(const char* __path, const char* __name) __INTRODUCED_IN(16); -int fremovexattr(int __fd, const char* __name) __INTRODUCED_IN(16); +/** + * [fgetxattr(2)](http://man7.org/linux/man-pages/man2/fgetxattr.2.html) + * gets an extended attribute on the file referred to by the given file + * descriptor. + * + * Returns the non-negative length of the value on success, or + * returns -1 and sets `errno` on failure. + */ +ssize_t fgetxattr(int __fd, const char* __name, void* __value, size_t __size); -__END_DECLS +/** + * [getxattr(2)](http://man7.org/linux/man-pages/man2/getxattr.2.html) + * gets an extended attribute on the file referred to by the given path. + * + * Returns the non-negative length of the value on success, or + * returns -1 and sets `errno` on failure. + */ +ssize_t getxattr(const char* __path, const char* __name, void* __value, size_t __size); + +/** + * [lgetxattr(2)](http://man7.org/linux/man-pages/man2/lgetxattr.2.html) + * gets an extended attribute on the file referred to by the given path, which + * is the link itself rather than its target in the case of a symbolic link. + * + * Returns the non-negative length of the value on success, or + * returns -1 and sets `errno` on failure. + */ +ssize_t lgetxattr(const char* __path, const char* __name, void* __value, size_t __size); -#endif +/** + * [flistxattr(2)](http://man7.org/linux/man-pages/man2/flistxattr.2.html) + * lists the extended attributes on the file referred to by the given file + * descriptor. + * + * Returns the non-negative length of the list on success, or + * returns -1 and sets `errno` on failure. + */ +ssize_t flistxattr(int __fd, char* __list, size_t __size); + +/** + * [listxattr(2)](http://man7.org/linux/man-pages/man2/listxattr.2.html) + * lists the extended attributes on the file referred to by the given path. + * + * Returns the non-negative length of the list on success, or + * returns -1 and sets `errno` on failure. + */ +ssize_t listxattr(const char* __path, char* __list, size_t __size); + +/** + * [llistxattr(2)](http://man7.org/linux/man-pages/man2/llistxattr.2.html) + * lists the extended attributes on the file referred to by the given path, which + * is the link itself rather than its target in the case of a symbolic link. + * + * Returns the non-negative length of the list on success, or + * returns -1 and sets `errno` on failure. + */ +ssize_t llistxattr(const char* __path, char* __list, size_t __size); + +/** + * [fremovexattr(2)](http://man7.org/linux/man-pages/man2/fremovexattr.2.html) + * removes an extended attribute on the file referred to by the given file + * descriptor. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + */ +int fremovexattr(int __fd, const char* __name); + +/** + * [lremovexattr(2)](http://man7.org/linux/man-pages/man2/lremovexattr.2.html) + * removes an extended attribute on the file referred to by the given path, which + * is the link itself rather than its target in the case of a symbolic link. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + */ +int lremovexattr(const char* __path, const char* __name); + +/** + * [removexattr(2)](http://man7.org/linux/man-pages/man2/removexattr.2.html) + * removes an extended attribute on the file referred to by the given path. + * + * Returns 0 on success and returns -1 and sets `errno` on failure. + */ +int removexattr(const char* __path, const char* __name); + +__END_DECLS diff --git a/libc/libc.map.txt b/libc/libc.map.txt index a4ab600fa..8e843af39 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -1468,10 +1468,10 @@ LIBC_Q { # introduced=Q __system_properties_init; # apex # Used by libmemunreachable - malloc_backtrace; # apex vndk - malloc_disable; # apex vndk - malloc_enable; # apex vndk - malloc_iterate; # apex vndk + malloc_backtrace; # apex llndk + malloc_disable; # apex llndk + malloc_enable; # apex llndk + malloc_iterate; # apex llndk # Used by libandroid_net android_getaddrinfofornet; # apex diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp index b5219a172..43bc4b61a 100644 --- a/libc/malloc_debug/PointerData.cpp +++ b/libc/malloc_debug/PointerData.cpp @@ -557,7 +557,7 @@ bool PointerData::Exists(const void* ptr) { return pointers_.count(pointer) != 0; } -void PointerData::DumpLiveToFile(FILE* fp) { +void PointerData::DumpLiveToFile(int fd) { std::vector<ListInfoType> list; std::lock_guard<std::mutex> pointer_guard(pointer_mutex_); @@ -569,13 +569,13 @@ void PointerData::DumpLiveToFile(FILE* fp) { total_memory += info.size * info.num_allocations; } - fprintf(fp, "Total memory: %zu\n", total_memory); - fprintf(fp, "Allocation records: %zd\n", list.size()); - fprintf(fp, "Backtrace size: %zu\n", g_debug->config().backtrace_frames()); - fprintf(fp, "\n"); + dprintf(fd, "Total memory: %zu\n", total_memory); + dprintf(fd, "Allocation records: %zd\n", list.size()); + dprintf(fd, "Backtrace size: %zu\n", g_debug->config().backtrace_frames()); + dprintf(fd, "\n"); for (const auto& info : list) { - fprintf(fp, "z %d sz %8zu num %zu bt", (info.zygote_child_alloc) ? 1 : 0, info.size, + dprintf(fd, "z %d sz %8zu num %zu bt", (info.zygote_child_alloc) ? 1 : 0, info.size, info.num_allocations); FrameInfoType* frame_info = info.frame_info; if (frame_info != nullptr) { @@ -583,22 +583,22 @@ void PointerData::DumpLiveToFile(FILE* fp) { if (frame_info->frames[i] == 0) { break; } - fprintf(fp, " %" PRIxPTR, frame_info->frames[i]); + dprintf(fd, " %" PRIxPTR, frame_info->frames[i]); } } - fprintf(fp, "\n"); + dprintf(fd, "\n"); if (info.backtrace_info != nullptr) { - fprintf(fp, " bt_info"); + dprintf(fd, " bt_info"); for (const auto& frame : *info.backtrace_info) { - fprintf(fp, " {"); + dprintf(fd, " {"); if (frame.map_info != nullptr && !frame.map_info->name.empty()) { - fprintf(fp, "\"%s\"", frame.map_info->name.c_str()); + dprintf(fd, "\"%s\"", frame.map_info->name.c_str()); } else { - fprintf(fp, "\"\""); + dprintf(fd, "\"\""); } - fprintf(fp, " %" PRIx64, frame.rel_pc); + dprintf(fd, " %" PRIx64, frame.rel_pc); if (frame.function_name.empty()) { - fprintf(fp, " \"\" 0}"); + dprintf(fd, " \"\" 0}"); } else { char* demangled_name = __cxa_demangle(frame.function_name.c_str(), nullptr, nullptr, nullptr); @@ -608,11 +608,11 @@ void PointerData::DumpLiveToFile(FILE* fp) { } else { name = frame.function_name.c_str(); } - fprintf(fp, " \"%s\" %" PRIx64 "}", name, frame.function_offset); + dprintf(fd, " \"%s\" %" PRIx64 "}", name, frame.function_offset); free(demangled_name); } } - fprintf(fp, "\n"); + dprintf(fd, "\n"); } } } diff --git a/libc/malloc_debug/PointerData.h b/libc/malloc_debug/PointerData.h index c7958f369..78f0ed862 100644 --- a/libc/malloc_debug/PointerData.h +++ b/libc/malloc_debug/PointerData.h @@ -152,7 +152,7 @@ class PointerData : public OptionData { static void GetAllocList(std::vector<ListInfoType>* list); static void LogLeaks(); - static void DumpLiveToFile(FILE* fp); + static void DumpLiveToFile(int fd); static void GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory, size_t* backtrace_size); diff --git a/libc/malloc_debug/exported32.map b/libc/malloc_debug/exported32.map index 8ed37faa2..f75d173df 100644 --- a/libc/malloc_debug/exported32.map +++ b/libc/malloc_debug/exported32.map @@ -8,13 +8,13 @@ LIBC_MALLOC_DEBUG { debug_free_malloc_leak_info; debug_get_malloc_leak_info; debug_initialize; - debug_iterate; debug_mallinfo; debug_malloc; debug_malloc_backtrace; debug_malloc_disable; debug_malloc_enable; debug_malloc_info; + debug_malloc_iterate; debug_malloc_usable_size; debug_mallopt; debug_memalign; diff --git a/libc/malloc_debug/exported64.map b/libc/malloc_debug/exported64.map index cdff88ba1..6dea58c42 100644 --- a/libc/malloc_debug/exported64.map +++ b/libc/malloc_debug/exported64.map @@ -8,13 +8,13 @@ LIBC_MALLOC_DEBUG { debug_free_malloc_leak_info; debug_get_malloc_leak_info; debug_initialize; - debug_iterate; debug_mallinfo; debug_malloc; debug_malloc_backtrace; debug_malloc_disable; debug_malloc_enable; debug_malloc_info; + debug_malloc_iterate; debug_malloc_usable_size; debug_mallopt; debug_memalign; diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp index d2679ca4c..3da694c75 100644 --- a/libc/malloc_debug/malloc_debug.cpp +++ b/libc/malloc_debug/malloc_debug.cpp @@ -97,8 +97,8 @@ struct mallinfo debug_mallinfo(); int debug_mallopt(int param, int value); int debug_malloc_info(int options, FILE* fp); int debug_posix_memalign(void** memptr, size_t alignment, size_t size); -int debug_iterate(uintptr_t base, size_t size, - void (*callback)(uintptr_t base, size_t size, void* arg), void* arg); +int debug_malloc_iterate(uintptr_t base, size_t size, + void (*callback)(uintptr_t base, size_t size, void* arg), void* arg); void debug_malloc_disable(); void debug_malloc_enable(); @@ -808,16 +808,23 @@ int debug_malloc_info(int options, FILE* fp) { if (DebugCallsDisabled() || !g_debug->TrackPointers()) { return g_dispatch->malloc_info(options, fp); } + + // Make sure any pending output is written to the file. + fflush(fp); + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; - MallocXmlElem root(fp, "malloc", "version=\"debug-malloc-1\""); + // Avoid any issues where allocations are made that will be freed + // in the fclose. + int fd = fileno(fp); + MallocXmlElem root(fd, "malloc", "version=\"debug-malloc-1\""); std::vector<ListInfoType> list; PointerData::GetAllocList(&list); size_t alloc_num = 0; for (size_t i = 0; i < list.size(); i++) { - MallocXmlElem alloc(fp, "allocation", "nr=\"%zu\"", alloc_num); + MallocXmlElem alloc(fd, "allocation", "nr=\"%zu\"", alloc_num); size_t total = 1; size_t size = list[i].size; @@ -825,8 +832,8 @@ int debug_malloc_info(int options, FILE* fp) { i++; total++; } - MallocXmlElem(fp, "size").Contents("%zu", list[i].size); - MallocXmlElem(fp, "total").Contents("%zu", total); + MallocXmlElem(fd, "size").Contents("%zu", list[i].size); + MallocXmlElem(fd, "total").Contents("%zu", total); alloc_num++; } return 0; @@ -857,7 +864,7 @@ int debug_posix_memalign(void** memptr, size_t alignment, size_t size) { return (*memptr != nullptr) ? 0 : ENOMEM; } -int debug_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_t, void*), +int debug_malloc_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_t, void*), void* arg) { ScopedConcurrentLock lock; if (g_debug->TrackPointers()) { @@ -870,7 +877,7 @@ int debug_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_ // An option that adds a header will add pointer tracking, so no need to // check if headers are enabled. - return g_dispatch->iterate(base, size, callback, arg); + return g_dispatch->malloc_iterate(base, size, callback, arg); } void debug_malloc_disable() { @@ -928,25 +935,28 @@ void* debug_valloc(size_t size) { static std::mutex g_dump_lock; -static void write_dump(FILE* fp) { - fprintf(fp, "Android Native Heap Dump v1.2\n\n"); +static void write_dump(int fd) { + dprintf(fd, "Android Native Heap Dump v1.2\n\n"); std::string fingerprint = android::base::GetProperty("ro.build.fingerprint", "unknown"); - fprintf(fp, "Build fingerprint: '%s'\n\n", fingerprint.c_str()); + dprintf(fd, "Build fingerprint: '%s'\n\n", fingerprint.c_str()); - PointerData::DumpLiveToFile(fp); + PointerData::DumpLiveToFile(fd); - fprintf(fp, "MAPS\n"); + dprintf(fd, "MAPS\n"); std::string content; if (!android::base::ReadFileToString("/proc/self/maps", &content)) { - fprintf(fp, "Could not open /proc/self/maps\n"); + dprintf(fd, "Could not open /proc/self/maps\n"); } else { - fprintf(fp, "%s", content.c_str()); + dprintf(fd, "%s", content.c_str()); } - fprintf(fp, "END\n"); + dprintf(fd, "END\n"); } bool debug_write_malloc_leak_info(FILE* fp) { + // Make sure any pending output is written to the file. + fflush(fp); + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; @@ -956,7 +966,8 @@ bool debug_write_malloc_leak_info(FILE* fp) { return false; } - write_dump(fp); + write_dump(fileno(fp)); + return true; } @@ -966,13 +977,13 @@ void debug_dump_heap(const char* file_name) { std::lock_guard<std::mutex> guard(g_dump_lock); - FILE* fp = fopen(file_name, "w+e"); - if (fp == nullptr) { + int fd = open(file_name, O_RDWR | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0644); + if (fd == -1) { error_log("Unable to create file: %s", file_name); return; } error_log("Dumping to file: %s\n", file_name); - write_dump(fp); - fclose(fp); + write_dump(fd); + close(fd); } diff --git a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp index 071675875..67bb8d936 100644 --- a/libc/malloc_debug/tests/malloc_debug_system_tests.cpp +++ b/libc/malloc_debug/tests/malloc_debug_system_tests.cpp @@ -37,6 +37,7 @@ #include <time.h> #include <unistd.h> +#include <android-base/file.h> #include <android-base/stringprintf.h> #include <gtest/gtest.h> #include <log/log.h> @@ -174,6 +175,7 @@ static void GetLogStr(pid_t pid, std::string* log_str, log_id log = LOG_ID_MAIN) } static void FindStrings(pid_t pid, std::vector<const char*> match_strings, + std::vector<const char*> no_match_strings = std::vector<const char*>{}, time_t timeout_seconds = kTimeoutSeconds) { std::string log_str; time_t start = time(nullptr); @@ -181,12 +183,18 @@ static void FindStrings(pid_t pid, std::vector<const char*> match_strings, while (true) { GetLogStr(pid, &log_str); found_all = true; + // Look for the expected strings. for (auto str : match_strings) { if (log_str.find(str) == std::string::npos) { found_all = false; break; } } + + // Verify the unexpected strings are not present. + for (auto str : no_match_strings) { + ASSERT_TRUE(log_str.find(str) == std::string::npos) << "Unexpectedly found '" << str << "' in log output:\n" << log_str; + } if (found_all) { return; } @@ -194,7 +202,7 @@ static void FindStrings(pid_t pid, std::vector<const char*> match_strings, break; } } - ASSERT_TRUE(found_all) << "Didn't find expected log output:\n" + log_str; + ASSERT_TRUE(found_all) << "Didn't find expected log output:\n" << log_str; } TEST(MallocTests, DISABLED_smoke) {} @@ -464,3 +472,45 @@ TEST(MallocDebugSystemTest, exit_while_threads_allocating) { << "Found crash in log.\nLog message: " << log_str; } } + +TEST(MallocTests, DISABLED_write_leak_info) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + + FILE* fp = fdopen(tf.fd, "w+"); + if (fp == nullptr) { + printf("Unable to create %s\n", tf.path); + _exit(1); + } + tf.release(); + + void* ptr = malloc(1000); + if (ptr == nullptr) { + printf("malloc failed\n"); + _exit(1); + } + memset(ptr, 0, 1000); + + android_mallopt(M_WRITE_MALLOC_LEAK_INFO_TO_FILE, fp, sizeof(fp)); + + fclose(fp); + + free(ptr); +} + +TEST(MallocDebugSystemTest, write_leak_info_no_header) { + pid_t pid; + ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_write_leak_info", "verbose backtrace", &pid, 0)); + + ASSERT_NO_FATAL_FAILURE(FindStrings(pid, std::vector<const char*>{"malloc debug enabled"}, + + std::vector<const char*>{" HAS INVALID TAG ", "USED AFTER FREE ", "UNKNOWN POINTER "})); +} + +TEST(MallocDebugSystemTest, write_leak_info_header) { + pid_t pid; + ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_write_leak_info", "verbose backtrace guard", &pid, 0)); + + ASSERT_NO_FATAL_FAILURE(FindStrings(pid, std::vector<const char*>{"malloc debug enabled"}, + std::vector<const char*>{" HAS INVALID TAG ", "USED AFTER FREE ", "UNKNOWN POINTER "})); +} diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp index 0238d1049..70457b9ad 100644 --- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp +++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp @@ -27,6 +27,8 @@ #include <algorithm> #include <memory> +#include <string> +#include <string_view> #include <thread> #include <vector> #include <utility> @@ -73,6 +75,9 @@ void* debug_pvalloc(size_t); void* debug_valloc(size_t); #endif +bool debug_write_malloc_leak_info(FILE*); +void debug_dump_heap(const char*); + __END_DECLS constexpr char DIVIDER[] = @@ -1302,6 +1307,10 @@ TEST_F(MallocDebugTest, get_malloc_backtrace_with_header) { } static std::string SanitizeHeapData(const std::string& data) { + if (data.empty()) { + return data; + } + // Remove the map data since it's not consistent. std::string sanitized; bool skip_map_data = false; @@ -1329,7 +1338,7 @@ static std::string SanitizeHeapData(const std::string& data) { sanitized += line + '\n'; } } - return sanitized; + return android::base::Trim(sanitized); } void MallocDebugTest::BacktraceDumpOnSignal(bool trigger_with_alloc) { @@ -1402,9 +1411,7 @@ z 1 sz 100 num 1 bt 100 200 z 1 sz 40 num 1 bt 300 400 MAPS MAP_DATA -END - -)"; +END)"; ASSERT_STREQ(expected.c_str(), sanitized.c_str()) << "Actual data: \n" << actual; ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -1463,9 +1470,7 @@ z 0 sz 400 num 1 bt a000 b000 z 0 sz 300 num 1 bt 100 200 MAPS MAP_DATA -END - -)"; +END)"; ASSERT_STREQ(expected.c_str(), sanitized.c_str()) << "Actual data: \n" << actual; ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -1513,9 +1518,7 @@ z 0 sz 400 num 1 bt a000 b000 c000 z 0 sz 300 num 2 bt 100 200 MAPS MAP_DATA -END - -)"; +END)"; ASSERT_STREQ(expected.c_str(), sanitized.c_str()) << "Actual data: \n" << actual; ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -1575,9 +1578,7 @@ z 0 sz 300 num 1 bt 1100 1200 bt_info {"" 100 "fake1" a} {"" 200 "fake2" 14} MAPS MAP_DATA -END - -)"; +END)"; ASSERT_STREQ(expected.c_str(), sanitized.c_str()) << "Actual data: \n" << actual; ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -2472,15 +2473,19 @@ TEST_F(MallocDebugTest, abort_on_error_header_tag_corrupted) { TEST_F(MallocDebugTest, malloc_info_no_pointer_tracking) { Init("fill"); - char* buffer; - size_t size; - FILE* memstream = open_memstream(&buffer, &size); - ASSERT_TRUE(memstream != nullptr); - ASSERT_EQ(0, debug_malloc_info(0, memstream)); - ASSERT_EQ(0, fclose(memstream)); + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + FILE* fp = fdopen(tf.fd, "w+"); + tf.release(); + ASSERT_TRUE(fp != nullptr); + ASSERT_EQ(0, debug_malloc_info(0, fp)); + ASSERT_EQ(0, fclose(fp)); + + std::string contents; + ASSERT_TRUE(android::base::ReadFileToString(tf.path, &contents)); tinyxml2::XMLDocument doc; - ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buffer)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(contents.c_str())); auto root = doc.FirstChildElement(); ASSERT_TRUE(root != nullptr); ASSERT_STREQ("malloc", root->Name()); @@ -2501,17 +2506,21 @@ TEST_F(MallocDebugTest, malloc_info_with_pointer_tracking) { std::unique_ptr<void, decltype(debug_free)*> ptr4(debug_malloc(1200), debug_free); ASSERT_TRUE(ptr4.get() != nullptr); - char* buffer; - size_t size; - FILE* memstream = open_memstream(&buffer, &size); - ASSERT_TRUE(memstream != nullptr); - ASSERT_EQ(0, debug_malloc_info(0, memstream)); - ASSERT_EQ(0, fclose(memstream)); + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + FILE* fp = fdopen(tf.fd, "w+"); + tf.release(); + ASSERT_TRUE(fp != nullptr); + ASSERT_EQ(0, debug_malloc_info(0, fp)); + ASSERT_EQ(0, fclose(fp)); - SCOPED_TRACE(testing::Message() << "Output:\n" << buffer); + std::string contents; + ASSERT_TRUE(android::base::ReadFileToString(tf.path, &contents)); + + SCOPED_TRACE(testing::Message() << "Output:\n" << contents); tinyxml2::XMLDocument doc; - ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buffer)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(contents.c_str())); auto root = doc.FirstChildElement(); ASSERT_TRUE(root != nullptr); ASSERT_STREQ("malloc", root->Name()); @@ -2548,3 +2557,134 @@ TEST_F(MallocDebugTest, malloc_info_with_pointer_tracking) { ASSERT_EQ(tinyxml2::XML_SUCCESS, alloc->FirstChildElement("total")->QueryIntText(&val)); ASSERT_EQ(1, val); } + +static void AllocPtrsWithBacktrace(std::vector<void*>* ptrs) { + backtrace_fake_add(std::vector<uintptr_t> {0xf, 0xe, 0xd, 0xc}); + void* ptr = debug_malloc(1024); + ASSERT_TRUE(ptr != nullptr); + memset(ptr, 0, 1024); + ptrs->push_back(ptr); + + backtrace_fake_add(std::vector<uintptr_t> {0xbc000, 0xbc001, 0xbc002}); + ptr = debug_malloc(500); + ASSERT_TRUE(ptr != nullptr); + memset(ptr, 0, 500); + ptrs->push_back(ptr); + + backtrace_fake_add(std::vector<uintptr_t> {0x104}); + ptr = debug_malloc(100); + ASSERT_TRUE(ptr != nullptr); + memset(ptr, 0, 100); + ptrs->push_back(ptr); +} + +static constexpr std::string_view kDumpInfo = R"(Android Native Heap Dump v1.2 + +Build fingerprint: '' + +Total memory: 1624 +Allocation records: 3 +Backtrace size: 16 + +z 0 sz 1024 num 1 bt f e d c +z 0 sz 500 num 1 bt bc000 bc001 bc002 +z 0 sz 100 num 1 bt 104 +MAPS +MAP_DATA +END)"; + +TEST_F(MallocDebugTest, debug_write_malloc_leak_info) { + Init("backtrace=16"); + + std::vector<void*> ptrs; + AllocPtrsWithBacktrace(&ptrs); + + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + close(tf.fd); + tf.release(); + FILE* fp = fopen(tf.path, "w+"); + ASSERT_TRUE(fp != nullptr); + + ASSERT_TRUE(debug_write_malloc_leak_info(fp)); + + fclose(fp); + + for (auto ptr : ptrs) { + debug_free(ptr); + } + ptrs.clear(); + + std::string expected(kDumpInfo); + + std::string contents; + ASSERT_TRUE(android::base::ReadFileToString(tf.path, &contents)); + contents = SanitizeHeapData(contents); + ASSERT_EQ(expected, contents); + ASSERT_STREQ("", getFakeLogBuf().c_str()); + ASSERT_STREQ("", getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugTest, debug_write_malloc_leak_info_extra_data) { + Init("backtrace=16"); + + std::vector<void*> ptrs; + AllocPtrsWithBacktrace(&ptrs); + + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + close(tf.fd); + tf.release(); + FILE* fp = fopen(tf.path, "w+"); + ASSERT_TRUE(fp != nullptr); + + fprintf(fp, "This message should appear before the output.\n"); + ASSERT_TRUE(debug_write_malloc_leak_info(fp)); + fprintf(fp, "This message should appear after the output.\n"); + + fclose(fp); + + for (auto ptr : ptrs) { + debug_free(ptr); + } + ptrs.clear(); + + std::string expected = "This message should appear before the output.\n" + + std::string(kDumpInfo) + + "\nThis message should appear after the output."; + + std::string contents; + ASSERT_TRUE(android::base::ReadFileToString(tf.path, &contents)); + contents = SanitizeHeapData(contents); + ASSERT_EQ(expected, contents); + ASSERT_STREQ("", getFakeLogBuf().c_str()); + ASSERT_STREQ("", getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugTest, dump_heap) { + Init("backtrace=16"); + + std::vector<void*> ptrs; + AllocPtrsWithBacktrace(&ptrs); + + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + close(tf.fd); + tf.release(); + debug_dump_heap(tf.path); + + for (auto ptr : ptrs) { + debug_free(ptr); + } + ptrs.clear(); + + std::string expected(kDumpInfo); + + std::string contents; + ASSERT_TRUE(android::base::ReadFileToString(tf.path, &contents)); + contents = SanitizeHeapData(contents); + ASSERT_EQ(expected, contents); + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string expected_log = std::string("6 malloc_debug Dumping to file: ") + tf.path + "\n\n"; + ASSERT_EQ(expected_log, getFakeLogPrint()); +} diff --git a/libc/malloc_hooks/exported32.map b/libc/malloc_hooks/exported32.map index 293d9ac15..2b028062b 100644 --- a/libc/malloc_hooks/exported32.map +++ b/libc/malloc_hooks/exported32.map @@ -7,13 +7,13 @@ LIBC_MALLOC_HOOKS { hooks_free_malloc_leak_info; hooks_get_malloc_leak_info; hooks_initialize; - hooks_iterate; hooks_mallinfo; hooks_malloc; hooks_malloc_backtrace; hooks_malloc_disable; hooks_malloc_enable; hooks_malloc_info; + hooks_malloc_iterate; hooks_malloc_usable_size; hooks_mallopt; hooks_memalign; diff --git a/libc/malloc_hooks/exported64.map b/libc/malloc_hooks/exported64.map index 340106b2e..59ec1f01f 100644 --- a/libc/malloc_hooks/exported64.map +++ b/libc/malloc_hooks/exported64.map @@ -7,13 +7,13 @@ LIBC_MALLOC_HOOKS { hooks_free_malloc_leak_info; hooks_get_malloc_leak_info; hooks_initialize; - hooks_iterate; hooks_mallinfo; hooks_malloc; hooks_malloc_backtrace; hooks_malloc_disable; hooks_malloc_enable; hooks_malloc_info; + hooks_malloc_iterate; hooks_malloc_usable_size; hooks_mallopt; hooks_memalign; diff --git a/libc/malloc_hooks/malloc_hooks.cpp b/libc/malloc_hooks/malloc_hooks.cpp index b1c1d5060..1ba869698 100644 --- a/libc/malloc_hooks/malloc_hooks.cpp +++ b/libc/malloc_hooks/malloc_hooks.cpp @@ -67,7 +67,7 @@ void* hooks_calloc(size_t nmemb, size_t bytes); struct mallinfo hooks_mallinfo(); int hooks_mallopt(int param, int value); int hooks_posix_memalign(void** memptr, size_t alignment, size_t size); -int hooks_iterate(uintptr_t base, size_t size, +int hooks_malloc_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t base, size_t size, void* arg), void* arg); void hooks_malloc_disable(); void hooks_malloc_enable(); @@ -209,7 +209,7 @@ int hooks_posix_memalign(void** memptr, size_t alignment, size_t size) { return g_dispatch->posix_memalign(memptr, alignment, size); } -int hooks_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) { +int hooks_malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) { return 0; } diff --git a/libc/private/MallocXmlElem.h b/libc/private/MallocXmlElem.h index 04d3eeea6..a36797261 100644 --- a/libc/private/MallocXmlElem.h +++ b/libc/private/MallocXmlElem.h @@ -18,38 +18,39 @@ #include <stdarg.h> #include <stdio.h> +#include <unistd.h> #include <private/bionic_macros.h> class MallocXmlElem { public: // Name must be valid throughout lifetime of the object. - explicit MallocXmlElem(FILE* fp, const char* name, - const char* attr_fmt = nullptr, ...) : fp_(fp), name_(name) { - fprintf(fp, "<%s", name_); + explicit MallocXmlElem(int fd, const char* name, + const char* attr_fmt = nullptr, ...) : fd_(fd), name_(name) { + dprintf(fd_, "<%s", name_); if (attr_fmt != nullptr) { va_list args; va_start(args, attr_fmt); - fputc(' ', fp_); - vfprintf(fp_, attr_fmt, args); + write(fd_, " ", 1); + vdprintf(fd_, attr_fmt, args); va_end(args); } - fputc('>', fp_); + write(fd_, ">", 1); } ~MallocXmlElem() noexcept { - fprintf(fp_, "</%s>", name_); + dprintf(fd_, "</%s>", name_); } void Contents(const char* fmt, ...) { va_list args; va_start(args, fmt); - vfprintf(fp_, fmt, args); + vdprintf(fd_, fmt, args); va_end(args); } private: - FILE* fp_; + int fd_; const char* name_; BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(MallocXmlElem); diff --git a/libc/private/ScopedFd.h b/libc/private/ScopedFd.h new file mode 100644 index 000000000..1cec91683 --- /dev/null +++ b/libc/private/ScopedFd.h @@ -0,0 +1,64 @@ +/* + * 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 <unistd.h> + +#include "private/bionic_macros.h" +#include "private/ErrnoRestorer.h" + +class ScopedFd final { + public: + explicit ScopedFd(int fd) : fd_(fd) { + } + + ScopedFd() : fd_(-1) { + } + + ~ScopedFd() { + reset(-1); + } + + void reset(int fd = -1) { + if (fd_ != -1) { + ErrnoRestorer e; + close(fd_); + } + fd_ = fd; + } + + int get() const { + return fd_; + } + + private: + int fd_; + + BIONIC_DISALLOW_COPY_AND_ASSIGN(ScopedFd); +}; diff --git a/libc/private/bionic_malloc_dispatch.h b/libc/private/bionic_malloc_dispatch.h index aea3a1c09..52d857317 100644 --- a/libc/private/bionic_malloc_dispatch.h +++ b/libc/private/bionic_malloc_dispatch.h @@ -70,7 +70,7 @@ struct MallocDispatch { #if defined(HAVE_DEPRECATED_MALLOC_FUNCS) MallocValloc valloc; #endif - MallocIterate iterate; + MallocIterate malloc_iterate; MallocMallocDisable malloc_disable; MallocMallocEnable malloc_enable; MallocMallopt mallopt; diff --git a/libc/system_properties/include/system_properties/prop_area.h b/libc/system_properties/include/system_properties/prop_area.h index a69f90eb1..53b27457e 100644 --- a/libc/system_properties/include/system_properties/prop_area.h +++ b/libc/system_properties/include/system_properties/prop_area.h @@ -106,6 +106,20 @@ class prop_area { memset(reserved_, 0, sizeof(reserved_)); // Allocate enough space for the root node. bytes_used_ = sizeof(prop_bt); + // To make property reads wait-free, we reserve a + // PROP_VALUE_MAX-sized block of memory, the "dirty backup area", + // just after the root node. When we're about to modify a + // property, we copy the old value into the dirty backup area and + // copy the new value into the prop_info structure. Before + // starting the latter copy, we mark the property's serial as + // being dirty. If a reader comes along while we're doing the + // property update and sees a dirty serial, the reader copies from + // the dirty backup area instead of the property value + // proper. After the copy, the reader checks whether the property + // serial is the same: if it is, the dirty backup area hasn't been + // reused for something else and we can complete the + // read immediately. + bytes_used_ += __BIONIC_ALIGN(PROP_VALUE_MAX, sizeof(uint_least32_t)); } const prop_info* find(const char* name); @@ -122,6 +136,9 @@ class prop_area { uint32_t version() const { return version_; } + char* dirty_backup_area() { + return data_ + sizeof (prop_bt); + } private: static prop_area* map_fd_ro(const int fd); diff --git a/libc/system_properties/include/system_properties/system_properties.h b/libc/system_properties/include/system_properties/system_properties.h index cad29cc72..0666e2803 100644 --- a/libc/system_properties/include/system_properties/system_properties.h +++ b/libc/system_properties/include/system_properties/system_properties.h @@ -66,7 +66,6 @@ class SystemProperties { int Get(const char* name, char* value); int Update(prop_info* pi, const char* value, unsigned int len); int Add(const char* name, unsigned int namelen, const char* value, unsigned int valuelen); - uint32_t Serial(const prop_info* pi); uint32_t WaitAny(uint32_t old_serial); bool Wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr, const timespec* relative_timeout); @@ -74,6 +73,8 @@ class SystemProperties { int Foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie); private: + uint32_t ReadMutablePropertyValue(const prop_info* pi, char* value); + // We don't want to use new or malloc in properties (b/31659220), and we don't want to waste a // full page by using mmap(), so we set aside enough space to create any context of the three // contexts. diff --git a/libc/system_properties/system_properties.cpp b/libc/system_properties/system_properties.cpp index d7c441b9b..840477858 100644 --- a/libc/system_properties/system_properties.cpp +++ b/libc/system_properties/system_properties.cpp @@ -140,42 +140,58 @@ static bool is_read_only(const char* name) { return strncmp(name, "ro.", 3) == 0; } -int SystemProperties::Read(const prop_info* pi, char* name, char* value) { - while (true) { - uint32_t serial = Serial(pi); // acquire semantics - size_t len = SERIAL_VALUE_LEN(serial); - memcpy(value, pi->value, len + 1); - // TODO: Fix the synchronization scheme here. - // There is no fully supported way to implement this kind - // of synchronization in C++11, since the memcpy races with - // updates to pi, and the data being accessed is not atomic. - // The following fence is unintuitive, but would be the - // correct one if memcpy used memory_order_relaxed atomic accesses. - // In practice it seems unlikely that the generated code would - // would be any different, so this should be OK. +uint32_t SystemProperties::ReadMutablePropertyValue(const prop_info* pi, char* value) { + // We assume the memcpy below gets serialized by the acquire fence. + uint32_t new_serial = load_const_atomic(&pi->serial, memory_order_acquire); + uint32_t serial; + unsigned int len; + for (;;) { + serial = new_serial; + len = SERIAL_VALUE_LEN(serial); + if (__predict_false(SERIAL_DIRTY(serial))) { + // See the comment in the prop_area constructor. + prop_area* pa = contexts_->GetPropAreaForName(pi->name); + memcpy(value, pa->dirty_backup_area(), len + 1); + } else { + memcpy(value, pi->value, len + 1); + } atomic_thread_fence(memory_order_acquire); - if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) { - if (name != nullptr) { - size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX); - if (namelen >= PROP_NAME_MAX) { - async_safe_format_log(ANDROID_LOG_ERROR, "libc", - "The property name length for \"%s\" is >= %d;" - " please use __system_property_read_callback" - " to read this property. (the name is truncated to \"%s\")", - pi->name, PROP_NAME_MAX - 1, name); - } - } - if (is_read_only(pi->name) && pi->is_long()) { - async_safe_format_log( - ANDROID_LOG_ERROR, "libc", - "The property \"%s\" has a value with length %zu that is too large for" - " __system_property_get()/__system_property_read(); use" - " __system_property_read_callback() instead.", - pi->name, strlen(pi->long_value())); - } - return len; + new_serial = load_const_atomic(&pi->serial, memory_order_relaxed); + if (__predict_true(serial == new_serial)) { + break; + } + // We need another fence here because we want to ensure that the memcpy in the + // next iteration of the loop occurs after the load of new_serial above. We could + // get this guarantee by making the load_const_atomic of new_serial + // memory_order_acquire instead of memory_order_relaxed, but then we'd pay the + // penalty of the memory_order_acquire even in the overwhelmingly common case + // that the serial number didn't change. + atomic_thread_fence(memory_order_acquire); + } + return serial; +} + +int SystemProperties::Read(const prop_info* pi, char* name, char* value) { + uint32_t serial = ReadMutablePropertyValue(pi, value); + if (name != nullptr) { + size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX); + if (namelen >= PROP_NAME_MAX) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "The property name length for \"%s\" is >= %d;" + " please use __system_property_read_callback" + " to read this property. (the name is truncated to \"%s\")", + pi->name, PROP_NAME_MAX - 1, name); } } + if (is_read_only(pi->name) && pi->is_long()) { + async_safe_format_log( + ANDROID_LOG_ERROR, "libc", + "The property \"%s\" has a value with length %zu that is too large for" + " __system_property_get()/__system_property_read(); use" + " __system_property_read_callback() instead.", + pi->name, strlen(pi->long_value())); + } + return SERIAL_VALUE_LEN(serial); } void SystemProperties::ReadCallback(const prop_info* pi, @@ -183,9 +199,9 @@ void SystemProperties::ReadCallback(const prop_info* pi, const char* value, uint32_t serial), void* cookie) { // Read only properties don't need to copy the value to a temporary buffer, since it can never - // change. + // change. We use relaxed memory order on the serial load for the same reason. if (is_read_only(pi->name)) { - uint32_t serial = Serial(pi); + uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed); if (pi->is_long()) { callback(cookie, pi->name, pi->long_value(), serial); } else { @@ -194,21 +210,9 @@ void SystemProperties::ReadCallback(const prop_info* pi, return; } - while (true) { - uint32_t serial = Serial(pi); // acquire semantics - size_t len = SERIAL_VALUE_LEN(serial); - char value_buf[len + 1]; - - memcpy(value_buf, pi->value, len); - value_buf[len] = '\0'; - - // TODO: see todo in Read function - atomic_thread_fence(memory_order_acquire); - if (serial == load_const_atomic(&(pi->serial), memory_order_relaxed)) { - callback(cookie, pi->name, value_buf, serial); - return; - } - } + char value_buf[PROP_VALUE_MAX]; + uint32_t serial = ReadMutablePropertyValue(pi, value_buf); + callback(cookie, pi->name, value_buf, serial); } int SystemProperties::Get(const char* name, char* value) { @@ -231,26 +235,37 @@ int SystemProperties::Update(prop_info* pi, const char* value, unsigned int len) return -1; } - prop_area* pa = contexts_->GetSerialPropArea(); - if (!pa) { + prop_area* serial_pa = contexts_->GetSerialPropArea(); + if (!serial_pa) { + return -1; + } + prop_area* pa = contexts_->GetPropAreaForName(pi->name); + if (__predict_false(!pa)) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find area for \"%s\"", pi->name); return -1; } uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_relaxed); + unsigned int old_len = SERIAL_VALUE_LEN(serial); + + // The contract with readers is that whenever the dirty bit is set, an undamaged copy + // of the pre-dirty value is available in the dirty backup area. The fence ensures + // that we publish our dirty area update before allowing readers to see a + // dirty serial. + memcpy(pa->dirty_backup_area(), pi->value, old_len + 1); + atomic_thread_fence(memory_order_release); serial |= 1; atomic_store_explicit(&pi->serial, serial, memory_order_relaxed); - // The memcpy call here also races. Again pretend it - // used memory_order_relaxed atomics, and use the analogous - // counterintuitive fence. - atomic_thread_fence(memory_order_release); strlcpy(pi->value, value, len + 1); - - atomic_store_explicit(&pi->serial, (len << 24) | ((serial + 1) & 0xffffff), memory_order_release); - __futex_wake(&pi->serial, INT32_MAX); - - atomic_store_explicit(pa->serial(), atomic_load_explicit(pa->serial(), memory_order_relaxed) + 1, + // Now the primary value property area is up-to-date. Let readers know that they should + // look at the property value instead of the backup area. + atomic_thread_fence(memory_order_release); + atomic_store_explicit(&pi->serial, (len << 24) | ((serial + 1) & 0xffffff), memory_order_relaxed); + __futex_wake(&pi->serial, INT32_MAX); // Fence by side effect + atomic_store_explicit(serial_pa->serial(), + atomic_load_explicit(serial_pa->serial(), memory_order_relaxed) + 1, memory_order_release); - __futex_wake(pa->serial(), INT32_MAX); + __futex_wake(serial_pa->serial(), INT32_MAX); return 0; } @@ -294,16 +309,6 @@ int SystemProperties::Add(const char* name, unsigned int namelen, const char* va return 0; } -// Wait for non-locked serial, and retrieve it with acquire semantics. -uint32_t SystemProperties::Serial(const prop_info* pi) { - uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire); - while (SERIAL_DIRTY(serial)) { - __futex_wait(const_cast<_Atomic(uint_least32_t)*>(&pi->serial), serial, nullptr); - serial = load_const_atomic(&pi->serial, memory_order_acquire); - } - return serial; -} - uint32_t SystemProperties::WaitAny(uint32_t old_serial) { uint32_t new_serial; Wait(nullptr, old_serial, &new_serial, nullptr); diff --git a/libm/Android.bp b/libm/Android.bp index bf05b1734..de32185f1 100644 --- a/libm/Android.bp +++ b/libm/Android.bp @@ -286,6 +286,7 @@ cc_library { pack_relocations: false, ldflags: ["-Wl,--hash-style=both"], version_script: ":libm.arm.map", + whole_static_libs: [ "libgcc_stripped" ], }, arm64: { diff --git a/linker/Android.bp b/linker/Android.bp index bb9d26d88..1800bdb2a 100644 --- a/linker/Android.bp +++ b/linker/Android.bp @@ -1,22 +1,6 @@ -cc_library_static { - name: "liblinker_malloc", - defaults: ["linux_bionic_supported"], - recovery_available: true, - native_bridge_supported: true, - - srcs: [ - "linker_memory.cpp", - ], - cflags: [ - "-Wall", - "-Werror", - ], - - // We need to access Bionic private headers in the linker. - include_dirs: ["bionic/libc"], - - static_libs: ["libasync_safe", "libbase"], -} +// ======================================================== +// linker_wrapper - Linux Bionic (on the host) +// ======================================================== // This is used for bionic on (host) Linux to bootstrap our linker embedded into // a binary. @@ -66,6 +50,103 @@ cc_object { include_dirs: ["bionic/libc"], } +// ======================================================== +// linker default configuration +// ======================================================== + +// Configuration for the linker binary and any of its static libraries. +cc_defaults { + name: "linker_defaults", + arch: { + arm: { + cflags: ["-D__work_around_b_24465209__"], + }, + x86: { + cflags: ["-D__work_around_b_24465209__"], + }, + }, + + cflags: [ + "-fno-stack-protector", + "-Wstrict-overflow=5", + "-fvisibility=hidden", + "-Wall", + "-Wextra", + "-Wunused", + "-Werror", + ], + + // TODO: split out the asflags. + asflags: [ + "-fno-stack-protector", + "-Wstrict-overflow=5", + "-fvisibility=hidden", + "-Wall", + "-Wextra", + "-Wunused", + "-Werror", + ], + + product_variables: { + debuggable: { + cppflags: ["-DUSE_LD_CONFIG_FILE"], + }, + }, + + cppflags: ["-Wold-style-cast"], + + static_libs: [ + "libziparchive", + "libbase", + "libz", + + "libasync_safe", + + "liblog", + ], + + // We need to access Bionic private headers in the linker. + include_dirs: ["bionic/libc"], +} + +// ======================================================== +// linker components +// ======================================================== + +// Enable a module on all targets the linker runs on (ordinary Android targets, Linux Bionic, and +// native bridge implementations). +cc_defaults { + name: "linker_all_targets", + defaults: ["linux_bionic_supported"], + recovery_available: true, + native_bridge_supported: true, +} + +cc_library_static { + name: "liblinker_main", + defaults: ["linker_defaults", "linker_all_targets"], + srcs: ["linker_main.cpp"], + + // Ensure that the compiler won't insert string function calls before ifuncs are resolved. + cflags: ["-ffreestanding"], +} + +cc_library_static { + name: "liblinker_malloc", + defaults: ["linker_defaults", "linker_all_targets"], + srcs: ["linker_memory.cpp"], +} + +cc_library_static { + name: "liblinker_debuggerd_stub", + defaults: ["linker_defaults", "linker_all_targets"], + srcs: ["linker_debuggerd_stub.cpp"], +} + +// ======================================================== +// template for the linker binary +// ======================================================== + filegroup { name: "linker_sources", srcs: [ @@ -79,7 +160,6 @@ filegroup { "linker_globals.cpp", "linker_libc_support.c", "linker_libcxx_support.cpp", - "linker_main.cpp", "linker_namespaces.cpp", "linker_logger.cpp", "linker_mapped_file_fragment.cpp", @@ -137,30 +217,50 @@ filegroup { ], } -filegroup { - name: "linker_version_script", - srcs: ["linker.generic.map"], -} - -filegroup { - name: "linker_version_script_arm", - srcs: ["linker.arm.map"], +cc_defaults { + name: "linker_version_script_overlay", + arch: { + arm: { version_script: "linker.arm.map" }, + arm64: { version_script: "linker.generic.map" }, + x86: { version_script: "linker.generic.map" }, + x86_64: { version_script: "linker.generic.map" }, + mips: { version_script: "linker.generic.map" }, + mips64: { version_script: "linker.generic.map" }, + }, } +// A template for the linker binary. May be inherited by native bridge implementations. cc_defaults { - name: "linker_defaults", + name: "linker_bin_template", + defaults: ["linker_defaults"], + + srcs: [":linker_sources"], + arch: { arm: { - cflags: ["-D__work_around_b_24465209__"], + srcs: [":linker_sources_arm"], + static_libs: ["libunwind_llvm"], + }, + arm64: { + srcs: [":linker_sources_arm64"], }, x86: { - cflags: ["-D__work_around_b_24465209__"], + srcs: [":linker_sources_x86"], + }, + x86_64: { + srcs: [":linker_sources_x86_64"], + }, + mips: { + srcs: [":linker_sources_mips"], + }, + mips64: { + srcs: [":linker_sources_mips64"], }, }, - // -shared is used to overwrite the -Bstatic and -static - // flags triggered by LOCAL_FORCE_STATIC_EXECUTABLE. - // This dynamic linker is actually a shared object linked with static libraries. + // -shared is used to overwrite the -Bstatic and -static flags triggered by enabling + // static_executable. This dynamic linker is actually a shared object linked with static + // libraries. ldflags: [ "-shared", "-Wl,-Bsymbolic", @@ -168,35 +268,6 @@ cc_defaults { "-Wl,-soname,ld-android.so", ], - cflags: [ - "-fno-stack-protector", - "-Wstrict-overflow=5", - "-fvisibility=hidden", - "-Wall", - "-Wextra", - "-Wunused", - "-Werror", - ], - - // TODO: split out the asflags. - asflags: [ - "-fno-stack-protector", - "-Wstrict-overflow=5", - "-fvisibility=hidden", - "-Wall", - "-Wextra", - "-Wunused", - "-Werror", - ], - - product_variables: { - debuggable: { - cppflags: ["-DUSE_LD_CONFIG_FILE"], - }, - }, - - cppflags: ["-Wold-style-cast"], - // we are going to link libc++_static manually because // when stl is not set to "none" build system adds libdl // to the list of static libraries which needs to be @@ -222,58 +293,15 @@ cc_defaults { sanitize: { hwaddress: false, }, -} - -cc_binary { - defaults: ["linux_bionic_supported", "linker_defaults"], - srcs: [ ":linker_sources" ], - - arch: { - arm: { - srcs: [ ":linker_sources_arm" ], - version_script: ":linker_version_script_arm", - static_libs: ["libunwind_llvm"], - }, - arm64: { - srcs: [":linker_sources_arm64"], - version_script: ":linker_version_script", - }, - x86: { - srcs: [":linker_sources_x86"], - version_script: ":linker_version_script", - }, - x86_64: { - srcs: [":linker_sources_x86_64"], - version_script: ":linker_version_script", - }, - mips: { - srcs: [":linker_sources_mips"], - version_script: ":linker_version_script", - }, - mips64: { - srcs: [":linker_sources_mips64"], - version_script: ":linker_version_script", - }, - }, - - // We need to access Bionic private headers in the linker. - include_dirs: ["bionic/libc"], static_libs: [ - "libc_nomalloc", - "libm", - "libziparchive", - "libbase", - "libz", - - "libasync_safe", + "liblinker_main", + "liblinker_malloc", - "liblog", "libc++_static", - - // Important: The liblinker_malloc should be the last library in the list - // to overwrite any other malloc implementations by other static libraries. - "liblinker_malloc", + "libc_nomalloc", + "libc_dynamic_dispatch", + "libm", ], // Ensure that if the linker needs __gnu_Unwind_Find_exidx, then the linker will have a @@ -287,9 +315,25 @@ cc_binary { // linker stops linking against libgcc.a's arm32 unwinder. whole_static_libs: ["libc_unwind_static"], + system_shared_libs: [], + + // Opt out of native_coverage when opting out of system_shared_libs + native_coverage: false, +} + +// ======================================================== +// linker[_asan][64] binary +// ======================================================== + +cc_binary { name: "linker", + defaults: [ + "linker_bin_template", + "linux_bionic_supported", + "linker_version_script_overlay", + ], + symlinks: ["linker_asan"], - recovery_available: true, multilib: { lib32: { cflags: ["-DLIB_PATH=\"lib\""], @@ -299,28 +343,38 @@ cc_binary { suffix: "64", }, }, - system_shared_libs: [], - // Opt out of native_coverage when opting out of system_shared_libs - native_coverage: false, + compile_multilib: "both", + xom: false, + + recovery_available: true, + apex_available: [ + "//apex_available:platform", + "com.android.runtime", + ], target: { android: { + srcs: [ + "linker_debuggerd_android.cpp", + ], static_libs: [ "libc++demangle", "libdebuggerd_handler_fallback", ], }, + linux_bionic: { + static_libs: [ + "liblinker_debuggerd_stub", + ], + } }, - compile_multilib: "both", - xom: false, - - apex_available: [ - "//apex_available:platform", - "com.android.runtime", - ], } +// ======================================================== +// assorted modules +// ======================================================== + sh_binary { name: "ldd", src: "ldd", @@ -347,25 +401,11 @@ cc_library { // for x86, exclude libgcc_eh.a for the same reasons as above arch: { - arm: { - version_script: "linker.arm.map", - }, - arm64: { - version_script: "linker.generic.map", - }, x86: { ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"], - version_script: "linker.generic.map", }, x86_64: { ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"], - version_script: "linker.generic.map", - }, - mips: { - version_script: "linker.generic.map", - }, - mips64: { - version_script: "linker.generic.map", }, }, @@ -379,7 +419,7 @@ cc_library { stl: "none", name: "ld-android", - defaults: ["linux_bionic_supported"], + defaults: ["linux_bionic_supported", "linker_version_script_overlay"], recovery_available: true, native_bridge_supported: true, diff --git a/linker/linker.cpp b/linker/linker.cpp index eedce7029..e09b2a4c8 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -1503,7 +1503,16 @@ static bool load_library(android_namespace_t* ns, // Open the file. int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath); if (fd == -1) { - DL_OPEN_ERR("library \"%s\" not found", name); + if (task->is_dt_needed()) { + if (needed_by->is_main_executable()) { + DL_OPEN_ERR("library \"%s\" not found: needed by main executable", name); + } else { + DL_OPEN_ERR("library \"%s\" not found: needed by %s in namespace %s", name, + needed_by->get_realpath(), task->get_start_from()->get_name()); + } + } else { + DL_OPEN_ERR("library \"%s\" not found", name); + } return false; } @@ -3162,7 +3171,10 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n", reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(load_bias + addend)); - { + // In the linker, ifuncs are called as soon as possible so that string functions work. + // We must not call them again. (e.g. On arm32, resolving an ifunc changes the meaning of + // the addend from a resolver function to the implementation.) + if (!is_linker()) { #if !defined(__LP64__) // When relocating dso with text_relocation .text segment is // not executable. We need to restore elf flags for this diff --git a/linker/linker_debuggerd.h b/linker/linker_debuggerd.h new file mode 100644 index 000000000..d70187902 --- /dev/null +++ b/linker/linker_debuggerd.h @@ -0,0 +1,31 @@ +/* + * 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 + +void linker_debuggerd_init(); diff --git a/linker/linker_debuggerd_android.cpp b/linker/linker_debuggerd_android.cpp new file mode 100644 index 000000000..b8c82f990 --- /dev/null +++ b/linker/linker_debuggerd_android.cpp @@ -0,0 +1,44 @@ +/* + * 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 "linker_debuggerd.h" + +#include "debuggerd/handler.h" +#include "private/bionic_globals.h" + +#include "linker_gdb_support.h" + +void linker_debuggerd_init() { + debuggerd_callbacks_t callbacks = { + .get_abort_message = []() { + return __libc_shared_globals()->abort_msg; + }, + .post_dump = ¬ify_gdb_of_libraries, + }; + debuggerd_init(&callbacks); +} diff --git a/linker/linker_debuggerd_stub.cpp b/linker/linker_debuggerd_stub.cpp new file mode 100644 index 000000000..631e6e48b --- /dev/null +++ b/linker/linker_debuggerd_stub.cpp @@ -0,0 +1,32 @@ +/* + * 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 "linker_debuggerd.h" + +void linker_debuggerd_init() { +} diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp index bea2e3c82..8ba947f31 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -32,6 +32,7 @@ #include <sys/auxv.h> #include "linker_debug.h" +#include "linker_debuggerd.h" #include "linker_cfi.h" #include "linker_gdb_support.h" #include "linker_globals.h" @@ -39,6 +40,8 @@ #include "linker_tls.h" #include "linker_utils.h" +#include "private/bionic_auxv.h" +#include "private/bionic_call_ifunc_resolver.h" #include "private/bionic_globals.h" #include "private/bionic_tls.h" #include "private/KernelArgumentBlock.h" @@ -46,9 +49,6 @@ #include "android-base/unique_fd.h" #include "android-base/strings.h" #include "android-base/stringprintf.h" -#ifdef __ANDROID__ -#include "debuggerd/handler.h" -#endif #include <async_safe/log.h> #include <bionic/libc_init_common.h> @@ -311,15 +311,7 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load __system_properties_init(); // may use 'environ' // Register the debuggerd signal handler. -#ifdef __ANDROID__ - debuggerd_callbacks_t callbacks = { - .get_abort_message = []() { - return __libc_shared_globals()->abort_msg; - }, - .post_dump = ¬ify_gdb_of_libraries, - }; - debuggerd_init(&callbacks); -#endif + linker_debuggerd_init(); g_linker_logger.ResetState(); @@ -575,6 +567,39 @@ static void set_bss_vma_name(soinfo* si) { } } +// TODO: There is a similar ifunc resolver calling loop in libc_init_static.cpp, but that version +// uses weak symbols, which don't work in the linker prior to its relocation. This version also +// supports a load bias. When we stop supporting the gold linker in the NDK, then maybe we can use +// non-weak definitions and merge the two loops. +#if defined(USE_RELA) +extern __LIBC_HIDDEN__ ElfW(Rela) __rela_iplt_start[], __rela_iplt_end[]; + +static void call_ifunc_resolvers(ElfW(Addr) load_bias) { + for (ElfW(Rela) *r = __rela_iplt_start; r != __rela_iplt_end; ++r) { + ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(r->r_offset + load_bias); + ElfW(Addr) resolver = r->r_addend + load_bias; + *offset = __bionic_call_ifunc_resolver(resolver); + } +} +#else +extern __LIBC_HIDDEN__ ElfW(Rel) __rel_iplt_start[], __rel_iplt_end[]; + +static void call_ifunc_resolvers(ElfW(Addr) load_bias) { + for (ElfW(Rel) *r = __rel_iplt_start; r != __rel_iplt_end; ++r) { + ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(r->r_offset + load_bias); + ElfW(Addr) resolver = *offset + load_bias; + *offset = __bionic_call_ifunc_resolver(resolver); + } +} +#endif + +// Usable before ifunc resolvers have been called. This function is compiled with -ffreestanding. +static void linker_memclr(void* dst, size_t cnt) { + for (size_t i = 0; i < cnt; ++i) { + reinterpret_cast<char*>(dst)[i] = '\0'; + } +} + // Detect an attempt to run the linker on itself. e.g.: // /system/bin/linker64 /system/bin/linker64 // Use priority-1 to run this constructor before other constructors. @@ -608,7 +633,8 @@ __linker_init_post_relocation(KernelArgumentBlock& args, soinfo& linker_so); extern "C" ElfW(Addr) __linker_init(void* raw_args) { // Initialize TLS early so system calls and errno work. KernelArgumentBlock args(raw_args); - bionic_tcb temp_tcb = {}; + bionic_tcb temp_tcb __attribute__((uninitialized)); + linker_memclr(&temp_tcb, sizeof(temp_tcb)); __libc_init_main_thread_early(args, &temp_tcb); // When the linker is run by itself (rather than as an interpreter for @@ -626,11 +652,15 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) { ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr); ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff); + // string.h functions must not be used prior to calling the linker's ifunc resolvers. + const ElfW(Addr) load_bias = get_elf_exec_load_bias(elf_hdr); + call_ifunc_resolvers(load_bias); + soinfo tmp_linker_so(nullptr, nullptr, nullptr, 0, 0); tmp_linker_so.base = linker_addr; tmp_linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum); - tmp_linker_so.load_bias = get_elf_exec_load_bias(elf_hdr); + tmp_linker_so.load_bias = load_bias; tmp_linker_so.dynamic = nullptr; tmp_linker_so.phdr = phdr; tmp_linker_so.phnum = elf_hdr->e_phnum; diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp index 9e463948a..b69da9702 100644 --- a/tests/dl_test.cpp +++ b/tests/dl_test.cpp @@ -204,7 +204,10 @@ TEST(dl, exec_with_ld_preload) { // The two libs are in ns2/ subdir. TEST(dl, exec_without_ld_config_file) { #if defined(__BIONIC__) - std::string error_message = "CANNOT LINK EXECUTABLE \"" + GetTestlibRoot() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n"; + std::string error_message = + "CANNOT LINK EXECUTABLE \"" + GetTestlibRoot() + + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" " + "not found: needed by main executable\n"; std::string helper = GetTestlibRoot() + "/ld_config_test_helper/ld_config_test_helper"; chmod(helper.c_str(), 0755); diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index e98d66ffd..7e772b840 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -28,6 +28,7 @@ #include <android/dlext.h> #include <android-base/file.h> #include <android-base/strings.h> +#include <android-base/test_utils.h> #include <sys/mman.h> #include <sys/types.h> @@ -1374,7 +1375,10 @@ TEST(dlext, ns_isolated) { void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); ASSERT_TRUE(handle2 == nullptr); - ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror()); + const char* error = dlerror(); + ASSERT_MATCH(error, + R"(dlopen failed: library "libnstest_private_external.so" not found: needed by )" + R"(\S+libnstest_root_not_isolated.so in namespace private_isolated1)"); // Check dlopen by absolute path handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); @@ -1502,7 +1506,9 @@ TEST(dlext, ns_shared) { void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); ASSERT_TRUE(handle2 == nullptr); - ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror()); + ASSERT_MATCH(dlerror(), + R"(dlopen failed: library "libnstest_private_external.so" not found: needed by )" + R"(\S+libnstest_root_not_isolated.so in namespace private_isolated_shared)"); // Check dlopen by absolute path handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); @@ -1762,7 +1768,10 @@ TEST(dlext, ns_isolated_rtld_global) { handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); ASSERT_TRUE(handle1 == nullptr); - ASSERT_STREQ("dlopen failed: library \"libnstest_public.so\" not found", dlerror()); + ASSERT_MATCH( + dlerror(), + R"(dlopen failed: library "libnstest_public.so" not found: needed by \S+libnstest_root.so)" + R"( in namespace isolated2)"); } TEST(dlext, ns_inaccessible_error_message) { diff --git a/tests/leak_test.cpp b/tests/leak_test.cpp index 3cc1a0a91..e0a3d5772 100644 --- a/tests/leak_test.cpp +++ b/tests/leak_test.cpp @@ -127,22 +127,20 @@ TEST(pthread_leak, join) { // http://b/36045112 TEST(pthread_leak, detach) { LeakChecker lc; - constexpr int kThreadCount = 100; - // Devices with low power cores/low number of cores can not finish test in time hence decreasing - // threads count to 90. - // http://b/129924384. - int threads_count = (sysconf(_SC_NPROCESSORS_CONF) > 2) ? kThreadCount : (kThreadCount - 10); + // Ancient devices with only 2 cores need a lower limit. + // http://b/129924384 and https://issuetracker.google.com/142210680. + const int thread_count = (sysconf(_SC_NPROCESSORS_CONF) > 2) ? 100 : 50; for (size_t pass = 0; pass < 1; ++pass) { - struct thread_data { pthread_barrier_t* barrier; pid_t* tid; } threads[kThreadCount] = {}; + struct thread_data { pthread_barrier_t* barrier; pid_t* tid; } threads[thread_count]; pthread_barrier_t barrier; - ASSERT_EQ(pthread_barrier_init(&barrier, nullptr, threads_count + 1), 0); + ASSERT_EQ(pthread_barrier_init(&barrier, nullptr, thread_count + 1), 0); // Start child threads. - pid_t tids[kThreadCount]; - for (int i = 0; i < threads_count; ++i) { + pid_t tids[thread_count]; + for (int i = 0; i < thread_count; ++i) { threads[i] = {&barrier, &tids[i]}; const auto thread_function = +[](void* ptr) -> void* { thread_data* data = static_cast<thread_data*>(ptr); @@ -158,7 +156,7 @@ TEST(pthread_leak, detach) { pthread_barrier_wait(&barrier); ASSERT_EQ(pthread_barrier_destroy(&barrier), 0); - WaitUntilAllThreadsExited(tids, threads_count); + WaitUntilAllThreadsExited(tids, thread_count); // A native bridge implementation might need a warm up pass to reach a steady state. // http://b/37920774. diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp index 0407553b2..ebbd24793 100644 --- a/tests/malloc_test.cpp +++ b/tests/malloc_test.cpp @@ -358,15 +358,20 @@ TEST(malloc, valloc_overflow) { TEST(malloc, malloc_info) { #ifdef __BIONIC__ SKIP_WITH_HWASAN; // hwasan does not implement malloc_info - char* buf; - size_t bufsize; - FILE* memstream = open_memstream(&buf, &bufsize); - ASSERT_NE(nullptr, memstream); - ASSERT_EQ(0, malloc_info(0, memstream)); - ASSERT_EQ(0, fclose(memstream)); + + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + FILE* fp = fdopen(tf.fd, "w+"); + tf.release(); + ASSERT_TRUE(fp != nullptr); + ASSERT_EQ(0, malloc_info(0, fp)); + ASSERT_EQ(0, fclose(fp)); + + std::string contents; + ASSERT_TRUE(android::base::ReadFileToString(tf.path, &contents)); tinyxml2::XMLDocument doc; - ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buf)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(contents.c_str())); auto root = doc.FirstChildElement(); ASSERT_NE(nullptr, root); @@ -416,17 +421,21 @@ TEST(malloc, malloc_info_matches_mallinfo) { #ifdef __BIONIC__ SKIP_WITH_HWASAN; // hwasan does not implement malloc_info - char* buf; - size_t bufsize; - FILE* memstream = open_memstream(&buf, &bufsize); - ASSERT_NE(nullptr, memstream); + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + FILE* fp = fdopen(tf.fd, "w+"); + tf.release(); + ASSERT_TRUE(fp != nullptr); size_t mallinfo_before_allocated_bytes = mallinfo().uordblks; - ASSERT_EQ(0, malloc_info(0, memstream)); + ASSERT_EQ(0, malloc_info(0, fp)); size_t mallinfo_after_allocated_bytes = mallinfo().uordblks; - ASSERT_EQ(0, fclose(memstream)); + ASSERT_EQ(0, fclose(fp)); + + std::string contents; + ASSERT_TRUE(android::base::ReadFileToString(tf.path, &contents)); tinyxml2::XMLDocument doc; - ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buf)); + ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(contents.c_str())); size_t total_allocated_bytes = 0; auto root = doc.FirstChildElement(); diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp index 245e42f7d..6d696c79f 100644 --- a/tests/system_properties_test.cpp +++ b/tests/system_properties_test.cpp @@ -340,9 +340,9 @@ TEST(properties, __system_property_serial) { ASSERT_EQ(0, system_properties.Add("property", 8, "value1", 6)); const prop_info* pi = system_properties.Find("property"); ASSERT_TRUE(pi != nullptr); - unsigned serial = system_properties.Serial(pi); + unsigned serial = __system_property_serial(pi); ASSERT_EQ(0, system_properties.Update(const_cast<prop_info*>(pi), "value2", 6)); - ASSERT_NE(serial, system_properties.Serial(pi)); + ASSERT_NE(serial, __system_property_serial(pi)); #else // __BIONIC__ GTEST_SKIP() << "bionic-only test"; #endif // __BIONIC__ @@ -389,7 +389,7 @@ TEST(properties, __system_property_wait) { prop_info* pi = const_cast<prop_info*>(system_properties.Find("property")); ASSERT_TRUE(pi != nullptr); - unsigned serial = system_properties.Serial(pi); + unsigned serial = __system_property_serial(pi); std::thread thread([&system_properties]() { prop_info* pi = const_cast<prop_info*>(system_properties.Find("property")); diff --git a/tests/system_properties_test2.cpp b/tests/system_properties_test2.cpp index b9936dd48..0953bdeb0 100644 --- a/tests/system_properties_test2.cpp +++ b/tests/system_properties_test2.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#include <gtest/gtest.h> - #include <errno.h> #include <sys/wait.h> #include <unistd.h> @@ -24,6 +22,10 @@ #include <sstream> #include <string> +#include <gtest/gtest.h> + +#include "utils.h" + #if defined(__BIONIC__) #include <sys/system_properties.h> int64_t NanoTime() { @@ -128,6 +130,29 @@ TEST(properties, smoke) { #endif // __BIONIC__ } +TEST(properties, no_fd_leaks) { +#if defined(__BIONIC__) + FdLeakChecker leak_checker; + std::stringstream ss; + ss << "debug.test." << getpid() << "." << NanoTime() << "."; + const std::string property_prefix = ss.str(); + const std::string property_name = property_prefix + "property1"; + + for (size_t i = 0; i < 100; ++i) { + char propvalue[PROP_VALUE_MAX]; + ASSERT_EQ(0, __system_property_set(property_name.c_str(), "value1")); + ASSERT_EQ(6, __system_property_get(property_name.c_str(), propvalue)); + ASSERT_STREQ("value1", propvalue); + + ASSERT_EQ(0, __system_property_set(property_name.c_str(), "value2")); + ASSERT_EQ(6, __system_property_get(property_name.c_str(), propvalue)); + ASSERT_STREQ("value2", propvalue); + } +#else // __BIONIC__ + GTEST_SKIP() << "bionic-only test"; +#endif // __BIONIC__ +} + TEST(properties, empty_value) { #if defined(__BIONIC__) char propvalue[PROP_VALUE_MAX]; @@ -136,13 +161,13 @@ TEST(properties, empty_value) { ss << "debug.test." << getpid() << "." << NanoTime() << "." << "property_empty"; const std::string property_name = ss.str(); - for (size_t i=0; i<1000; ++i) { + for (size_t i = 0; i < 1000; ++i) { ASSERT_EQ(0, __system_property_set(property_name.c_str(), "")); ASSERT_EQ(0, __system_property_get(property_name.c_str(), propvalue)); ASSERT_STREQ("", propvalue); } -#else // __BIONIC__ - GTEST_SKIP() << "bionic-only test"; +#else // __BIONIC__ + GTEST_SKIP() << "bionic-only test"; #endif // __BIONIC__ } diff --git a/tests/utils.h b/tests/utils.h index 1f4cece19..cfc68c9a3 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -16,6 +16,7 @@ #pragma once +#include <dirent.h> #include <dlfcn.h> #include <fcntl.h> #include <inttypes.h> @@ -253,3 +254,29 @@ class ExecTestHelper { std::string output_; }; #endif + +class FdLeakChecker { + public: + FdLeakChecker() { + } + + ~FdLeakChecker() { + size_t end_count = CountOpenFds(); + EXPECT_EQ(start_count_, end_count); + } + + private: + static size_t CountOpenFds() { + auto fd_dir = std::unique_ptr<DIR, decltype(&closedir)>{ opendir("/proc/self/fd"), closedir }; + size_t count = 0; + dirent* de = nullptr; + while ((de = readdir(fd_dir.get())) != nullptr) { + if (de->d_type == DT_LNK) { + ++count; + } + } + return count; + } + + size_t start_count_ = CountOpenFds(); +}; diff --git a/tools/versioner/src/Driver.cpp b/tools/versioner/src/Driver.cpp index d2c50a96b..bad63ad2d 100644 --- a/tools/versioner/src/Driver.cpp +++ b/tools/versioner/src/Driver.cpp @@ -126,14 +126,7 @@ static void generateTargetCC1Flags(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSyste cmd.push_back("-DANDROID"); cmd.push_back("-D__ANDROID_API__="s + std::to_string(type.api_level)); - // FIXME: Re-enable FORTIFY properly once our clang in external/ is new enough - // to support diagnose_if without giving us syntax errors. -#if 0 cmd.push_back("-D_FORTIFY_SOURCE=2"); -#else - cmd.push_back("-D_FORTIFY_SOURCE=0"); - cmd.push_back("-D__BIONIC_DECLARE_FORTIFY_HELPERS"); -#endif cmd.push_back("-D_GNU_SOURCE"); cmd.push_back("-D_FILE_OFFSET_BITS="s + std::to_string(type.file_offset_bits)); |