diff options
Diffstat (limited to 'libc')
-rw-r--r-- | libc/Android.bp | 13 | ||||
-rw-r--r-- | libc/arch-arm/bionic/bpabi.c | 43 | ||||
-rw-r--r-- | libc/arch-arm/dynamic_function_dispatch.cpp | 12 | ||||
-rw-r--r-- | libc/bionic/grp_pwd.cpp | 82 | ||||
-rw-r--r-- | libc/bionic/libc_init_common.cpp | 2 | ||||
-rw-r--r-- | libc/bionic/malloc_common.cpp | 9 | ||||
-rw-r--r-- | libc/bionic/malloc_common_dynamic.cpp | 59 | ||||
-rw-r--r-- | libc/bionic/pthread_getschedparam.cpp | 2 | ||||
-rw-r--r-- | libc/bionic/pthread_setschedparam.cpp | 3 | ||||
-rw-r--r-- | libc/bionic/threads.cpp | 32 | ||||
-rw-r--r-- | libc/include/android/api-level.h | 3 | ||||
-rw-r--r-- | libc/include/android/legacy_threads_inlines.h (renamed from libc/arch-arm/dynamic_function_wrapper.S) | 17 | ||||
-rw-r--r-- | libc/include/bits/threads_inlines.h | 207 | ||||
-rw-r--r-- | libc/include/threads.h | 228 | ||||
-rw-r--r-- | libc/libc.map.txt | 36 | ||||
-rw-r--r-- | libc/malloc_hooks/tests/malloc_hooks_tests.cpp | 23 | ||||
-rw-r--r-- | libc/private/bionic_malloc.h | 36 | ||||
-rw-r--r-- | libc/stdlib/atexit.c | 5 |
18 files changed, 680 insertions, 132 deletions
diff --git a/libc/Android.bp b/libc/Android.bp index d8a1d70d5..174783fa6 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -762,12 +762,13 @@ cc_library_static { "arch-arm/generic/bionic/strlen.c", "arch-arm/bionic/__aeabi_read_tp.S", - "arch-arm/bionic/atomics_arm.c", "arch-arm/bionic/__bionic_clone.S", + "arch-arm/bionic/__restore.S", "arch-arm/bionic/_exit_with_stack_teardown.S", + "arch-arm/bionic/atomics_arm.c", + "arch-arm/bionic/bpabi.c", "arch-arm/bionic/libcrt_compat.c", "arch-arm/bionic/popcount_tab.c", - "arch-arm/bionic/__restore.S", "arch-arm/bionic/setjmp.S", "arch-arm/bionic/syscall.S", "arch-arm/bionic/vfork.S", @@ -1153,6 +1154,7 @@ cc_library_static { "bionic/tdestroy.cpp", "bionic/termios.cpp", "bionic/thread_private.cpp", + "bionic/threads.cpp", "bionic/timespec_get.cpp", "bionic/tmpfile.cpp", "bionic/umount.cpp", @@ -1461,12 +1463,7 @@ cc_library_static { srcs: ["arch-x86/dynamic_function_dispatch.cpp"], }, arm: { - srcs: [ - "arch-arm/dynamic_function_dispatch.cpp", - - // Workaround for b/120254692. - "arch-arm/dynamic_function_wrapper.S", - ], + srcs: ["arch-arm/dynamic_function_dispatch.cpp"], }, }, diff --git a/libc/arch-arm/bionic/bpabi.c b/libc/arch-arm/bionic/bpabi.c new file mode 100644 index 000000000..5c9cd99c6 --- /dev/null +++ b/libc/arch-arm/bionic/bpabi.c @@ -0,0 +1,43 @@ +/* + * 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. + */ + +extern long long __divdi3(long long, long long); +extern unsigned long long __udivdi3(unsigned long long, unsigned long long); + +long long __gnu_ldivmod_helper(long long a, long long b, long long* remainder) { + long long quotient = __divdi3(a, b); + *remainder = a - b * quotient; + return quotient; +} + +unsigned long long __gnu_uldivmod_helper(unsigned long long a, unsigned long long b, + unsigned long long* remainder) { + unsigned long long quotient = __udivdi3(a, b); + *remainder = a - b * quotient; + return quotient; +} diff --git a/libc/arch-arm/dynamic_function_dispatch.cpp b/libc/arch-arm/dynamic_function_dispatch.cpp index 09fd8f30e..640f3306a 100644 --- a/libc/arch-arm/dynamic_function_dispatch.cpp +++ b/libc/arch-arm/dynamic_function_dispatch.cpp @@ -89,15 +89,11 @@ static int ifunc_close(int fd) { return r0; } -#define DEFINE_IFUNC_WITH_SUFFIX(name, suffix) \ - name##_func name##suffix __attribute__((ifunc(#name "_resolver"))); \ +#define DEFINE_IFUNC(name) \ + name##_func name __attribute__((ifunc(#name "_resolver"))); \ __attribute__((visibility("hidden"))) \ name##_func* name##_resolver() -#define DEFINE_IFUNC(name) DEFINE_IFUNC_WITH_SUFFIX(name, ) - -#define DEFINE_INTERNAL_IFUNC(name) DEFINE_IFUNC_WITH_SUFFIX(name, _internal) - #define DECLARE_FUNC(type, name) \ __attribute__((visibility("hidden"))) \ type name @@ -291,7 +287,7 @@ DEFINE_IFUNC(__strcat_chk) { } typedef int strcmp_func(const char* __lhs, const char* __rhs); -DEFINE_INTERNAL_IFUNC(strcmp) { +DEFINE_IFUNC(strcmp) { switch(get_cpu_variant()) { case kCortexA9: RETURN_FUNC(strcmp_func, strcmp_a9); @@ -305,7 +301,7 @@ DEFINE_INTERNAL_IFUNC(strcmp) { } typedef size_t strlen_func(const char* __s); -DEFINE_INTERNAL_IFUNC(strlen) { +DEFINE_IFUNC(strlen) { switch(get_cpu_variant()) { case kCortexA9: RETURN_FUNC(strlen_func, strlen_a9); diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp index dadda49cb..ca6ea220c 100644 --- a/libc/bionic/grp_pwd.cpp +++ b/libc/bionic/grp_pwd.cpp @@ -163,37 +163,19 @@ static group* android_iinfo_to_group(group_state_t* state, return gr; } -static passwd* android_id_to_passwd(passwd_state_t* state, unsigned id) { +static const android_id_info* find_android_id_info(unsigned id) { for (size_t n = 0; n < android_id_count; ++n) { if (android_ids[n].aid == id) { - return android_iinfo_to_passwd(state, android_ids + n); + return &android_ids[n]; } } return nullptr; } -static passwd* android_name_to_passwd(passwd_state_t* state, const char* name) { +static const android_id_info* find_android_id_info(const char* name) { for (size_t n = 0; n < android_id_count; ++n) { if (!strcmp(android_ids[n].name, name)) { - return android_iinfo_to_passwd(state, android_ids + n); - } - } - return nullptr; -} - -static group* android_id_to_group(group_state_t* state, unsigned id) { - for (size_t n = 0; n < android_id_count; ++n) { - if (android_ids[n].aid == id) { - return android_iinfo_to_group(state, android_ids + n); - } - } - return nullptr; -} - -static group* android_name_to_group(group_state_t* state, const char* name) { - for (size_t n = 0; n < android_id_count; ++n) { - if (!strcmp(android_ids[n].name, name)) { - return android_iinfo_to_group(state, android_ids + n); + return &android_ids[n]; } } return nullptr; @@ -332,15 +314,9 @@ static id_t app_id_from_name(const char* name, bool is_group) { } else if (end[1] == 'i' && isdigit(end[2])) { // end will point to \0 if the strtoul below succeeds. appid = strtoul(end+2, &end, 10) + AID_ISOLATED_START; - } else { - for (size_t n = 0; n < android_id_count; n++) { - if (!strcmp(android_ids[n].name, end + 1)) { - appid = android_ids[n].aid; - // Move the end pointer to the null terminator. - end += strlen(android_ids[n].name) + 1; - break; - } - } + } else if (auto* android_id_info = find_android_id_info(end + 1); android_id_info != nullptr) { + appid = android_id_info->aid; + end += strlen(android_id_info->name) + 1; } // Check that the entire string was consumed by one of the 3 cases above. @@ -370,11 +346,8 @@ static void print_app_name_from_uid(const uid_t uid, char* buffer, const int buf if (appid >= AID_ISOLATED_START) { snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START); } else if (appid < AID_APP_START) { - for (size_t n = 0; n < android_id_count; n++) { - if (android_ids[n].aid == appid) { - snprintf(buffer, bufferlen, "u%u_%s", userid, android_ids[n].name); - return; - } + if (auto* android_id_info = find_android_id_info(appid); android_id_info != nullptr) { + snprintf(buffer, bufferlen, "u%u_%s", userid, android_id_info->name); } } else { snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP_START); @@ -391,11 +364,8 @@ static void print_app_name_from_gid(const gid_t gid, char* buffer, const int buf } else if (appid >= AID_CACHE_GID_START && appid <= AID_CACHE_GID_END) { snprintf(buffer, bufferlen, "u%u_a%u_cache", userid, appid - AID_CACHE_GID_START); } else if (appid < AID_APP_START) { - for (size_t n = 0; n < android_id_count; n++) { - if (android_ids[n].aid == appid) { - snprintf(buffer, bufferlen, "u%u_%s", userid, android_ids[n].name); - return; - } + if (auto* android_id_info = find_android_id_info(appid); android_id_info != nullptr) { + snprintf(buffer, bufferlen, "u%u_%s", userid, android_id_info->name); } } else { snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP_START); @@ -520,12 +490,12 @@ passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function. return nullptr; } - passwd* pw = android_id_to_passwd(state, uid); - if (pw != nullptr) { - return pw; + if (auto* android_id_info = find_android_id_info(uid); android_id_info != nullptr) { + return android_iinfo_to_passwd(state, android_id_info); } + // Handle OEM range. - pw = oem_id_to_passwd(uid, state); + passwd* pw = oem_id_to_passwd(uid, state); if (pw != nullptr) { return pw; } @@ -538,9 +508,8 @@ passwd* getpwnam(const char* login) { // NOLINT: implementing bad function. return nullptr; } - passwd* pw = android_name_to_passwd(state, login); - if (pw != nullptr) { - return pw; + if (auto* android_id_info = find_android_id_info(login); android_id_info != nullptr) { + return android_iinfo_to_passwd(state, android_id_info); } if (vendor_passwd.FindByName(login, state)) { @@ -550,7 +519,7 @@ passwd* getpwnam(const char* login) { // NOLINT: implementing bad function. } // Handle OEM range. - pw = oem_id_to_passwd(oem_id_from_name(login), state); + passwd* pw = oem_id_to_passwd(oem_id_from_name(login), state); if (pw != nullptr) { return pw; } @@ -634,12 +603,12 @@ passwd* getpwent() { } static group* getgrgid_internal(gid_t gid, group_state_t* state) { - group* grp = android_id_to_group(state, gid); - if (grp != nullptr) { - return grp; + if (auto* android_id_info = find_android_id_info(gid); android_id_info != nullptr) { + return android_iinfo_to_group(state, android_id_info); } + // Handle OEM range. - grp = oem_id_to_group(gid, state); + group* grp = oem_id_to_group(gid, state); if (grp != nullptr) { return grp; } @@ -655,9 +624,8 @@ group* getgrgid(gid_t gid) { // NOLINT: implementing bad function. } static group* getgrnam_internal(const char* name, group_state_t* state) { - group* grp = android_name_to_group(state, name); - if (grp != nullptr) { - return grp; + if (auto* android_id_info = find_android_id_info(name); android_id_info != nullptr) { + return android_iinfo_to_group(state, android_id_info); } if (vendor_group.FindByName(name, state)) { @@ -667,7 +635,7 @@ static group* getgrnam_internal(const char* name, group_state_t* state) { } // Handle OEM range. - grp = oem_id_to_group(oem_id_from_name(name), state); + group* grp = oem_id_to_group(oem_id_from_name(name), state); if (grp != nullptr) { return grp; } diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp index b229cda2f..1f099cfcc 100644 --- a/libc/bionic/libc_init_common.cpp +++ b/libc/bionic/libc_init_common.cpp @@ -232,6 +232,7 @@ static bool __is_unsafe_environment_variable(const char* name) { "LD_AOUT_LIBRARY_PATH", "LD_AOUT_PRELOAD", "LD_AUDIT", + "LD_CONFIG_FILE", "LD_DEBUG", "LD_DEBUG_OUTPUT", "LD_DYNAMIC_WEAK", @@ -242,6 +243,7 @@ static bool __is_unsafe_environment_variable(const char* name) { "LD_SHOW_AUXV", "LD_USE_LOAD_BIAS", "LIBC_DEBUG_MALLOC_OPTIONS", + "LIBC_HOOKS_ENABLE", "LOCALDOMAIN", "LOCPATH", "MALLOC_CHECK_", diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index e9f9db20a..9dc4d12d1 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -32,14 +32,7 @@ // calls and add special debugging code to attempt to catch allocation // errors. All of the debugging code is implemented in a separate shared // library that is only loaded when the property "libc.debug.malloc.options" -// is set to a non-zero value. There are two functions exported to -// allow ddms, or other external users to get information from the debug -// allocation. -// get_malloc_leak_info: Returns information about all of the known native -// allocations that are currently in use. -// free_malloc_leak_info: Frees the data allocated by the call to -// get_malloc_leak_info. -// write_malloc_leak_info: Writes the leak info data to a file. +// is set to a non-zero value. #include <errno.h> #include <stdint.h> diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp index 64f9f6f7b..599ac6a58 100644 --- a/libc/bionic/malloc_common_dynamic.cpp +++ b/libc/bionic/malloc_common_dynamic.cpp @@ -409,39 +409,29 @@ __LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) { // ============================================================================= // Functions to support dumping of native heap allocations using malloc debug. // ============================================================================= - -// Retrieve native heap information. -// -// "*info" is set to a buffer we allocate -// "*overall_size" is set to the size of the "info" buffer -// "*info_size" is set to the size of a single entry -// "*total_memory" is set to the sum of all allocations we're tracking; does -// not include heap overhead -// "*backtrace_size" is set to the maximum number of entries in the back trace -extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overall_size, - size_t* info_size, size_t* total_memory, size_t* backtrace_size) { +bool GetMallocLeakInfo(android_mallopt_leak_info_t* leak_info) { void* func = gFunctions[FUNC_GET_MALLOC_LEAK_INFO]; if (func == nullptr) { - return; + errno = ENOTSUP; + return false; } - reinterpret_cast<get_malloc_leak_info_func_t>(func)(info, overall_size, info_size, total_memory, - backtrace_size); + reinterpret_cast<get_malloc_leak_info_func_t>(func)( + &leak_info->buffer, &leak_info->overall_size, &leak_info->info_size, + &leak_info->total_memory, &leak_info->backtrace_size); + return true; } -extern "C" void free_malloc_leak_info(uint8_t* info) { +bool FreeMallocLeakInfo(android_mallopt_leak_info_t* leak_info) { void* func = gFunctions[FUNC_FREE_MALLOC_LEAK_INFO]; if (func == nullptr) { - return; + errno = ENOTSUP; + return false; } - reinterpret_cast<free_malloc_leak_info_func_t>(func)(info); + reinterpret_cast<free_malloc_leak_info_func_t>(func)(leak_info->buffer); + return true; } -extern "C" void write_malloc_leak_info(FILE* fp) { - if (fp == nullptr) { - error_log("write_malloc_leak_info called with a nullptr"); - return; - } - +bool WriteMallocLeakInfo(FILE* fp) { void* func = gFunctions[FUNC_WRITE_LEAK_INFO]; bool written = false; if (func != nullptr) { @@ -453,7 +443,9 @@ extern "C" void write_malloc_leak_info(FILE* fp) { fprintf(fp, "# adb shell stop\n"); fprintf(fp, "# adb shell setprop libc.debug.malloc.options backtrace\n"); fprintf(fp, "# adb shell start\n"); + errno = ENOTSUP; } + return written; } // ============================================================================= @@ -484,6 +476,27 @@ extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) { if (opcode == M_SET_ALLOCATION_LIMIT_BYTES) { return LimitEnable(arg, arg_size); } + if (opcode == M_WRITE_MALLOC_LEAK_INFO_TO_FILE) { + if (arg == nullptr || arg_size != sizeof(FILE*)) { + errno = EINVAL; + return false; + } + return WriteMallocLeakInfo(reinterpret_cast<FILE*>(arg)); + } + if (opcode == M_GET_MALLOC_LEAK_INFO) { + if (arg == nullptr || arg_size != sizeof(android_mallopt_leak_info_t)) { + errno = EINVAL; + return false; + } + return GetMallocLeakInfo(reinterpret_cast<android_mallopt_leak_info_t*>(arg)); + } + if (opcode == M_FREE_MALLOC_LEAK_INFO) { + if (arg == nullptr || arg_size != sizeof(android_mallopt_leak_info_t)) { + errno = EINVAL; + return false; + } + return FreeMallocLeakInfo(reinterpret_cast<android_mallopt_leak_info_t*>(arg)); + } return HeapprofdMallopt(opcode, arg, arg_size); } // ============================================================================= diff --git a/libc/bionic/pthread_getschedparam.cpp b/libc/bionic/pthread_getschedparam.cpp index ed1853bdc..765287fa4 100644 --- a/libc/bionic/pthread_getschedparam.cpp +++ b/libc/bionic/pthread_getschedparam.cpp @@ -28,9 +28,11 @@ #include <errno.h> +#include "private/bionic_defs.h" #include "private/ErrnoRestorer.h" #include "pthread_internal.h" +__BIONIC_WEAK_FOR_NATIVE_BRIDGE int pthread_getschedparam(pthread_t t, int* policy, sched_param* param) { ErrnoRestorer errno_restorer; diff --git a/libc/bionic/pthread_setschedparam.cpp b/libc/bionic/pthread_setschedparam.cpp index 8a0272868..656fe3208 100644 --- a/libc/bionic/pthread_setschedparam.cpp +++ b/libc/bionic/pthread_setschedparam.cpp @@ -30,9 +30,11 @@ #include <pthread.h> #include <sched.h> +#include "private/bionic_defs.h" #include "private/ErrnoRestorer.h" #include "pthread_internal.h" +__BIONIC_WEAK_FOR_NATIVE_BRIDGE int pthread_setschedparam(pthread_t t, int policy, const sched_param* param) { ErrnoRestorer errno_restorer; @@ -42,6 +44,7 @@ int pthread_setschedparam(pthread_t t, int policy, const sched_param* param) { return (sched_setscheduler(tid, policy, param) == -1) ? errno : 0; } +__BIONIC_WEAK_FOR_NATIVE_BRIDGE int pthread_setschedprio(pthread_t t, int priority) { ErrnoRestorer errno_restorer; diff --git a/libc/bionic/threads.cpp b/libc/bionic/threads.cpp new file mode 100644 index 000000000..f59758013 --- /dev/null +++ b/libc/bionic/threads.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 <threads.h> + +#define __BIONIC_THREADS_INLINE /* Out of line. */ +#include <bits/threads_inlines.h> diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h index a17585768..af7cde1e3 100644 --- a/libc/include/android/api-level.h +++ b/libc/include/android/api-level.h @@ -100,6 +100,9 @@ __BEGIN_DECLS /** Names the "Q" API level (29), for comparisons against __ANDROID_API__. */ #define __ANDROID_API_Q__ 29 +/** Names the "R" API level (30), for comparisons against __ANDROID_API__. */ +#define __ANDROID_API_R__ 30 + /** * Returns the `targetSdkVersion` of the caller, or `__ANDROID_API_FUTURE__` * if there is no known target SDK version (for code not running in the diff --git a/libc/arch-arm/dynamic_function_wrapper.S b/libc/include/android/legacy_threads_inlines.h index 1d2842b5c..e73ef37c7 100644 --- a/libc/arch-arm/dynamic_function_wrapper.S +++ b/libc/include/android/legacy_threads_inlines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,12 +26,13 @@ * SUCH DAMAGE. */ -#include <private/bionic_asm.h> +#pragma once -#define FUNCTION_DELEGATE(name, impl) \ -ENTRY(name); \ - b impl; \ -END(name) +#include <sys/cdefs.h> -FUNCTION_DELEGATE(strcmp, strcmp_internal) -FUNCTION_DELEGATE(strlen, strlen_internal) +#if __ANDROID_API__ < __ANDROID_API_R__ + +#define __BIONIC_THREADS_INLINE static __inline +#include <bits/threads_inlines.h> + +#endif diff --git a/libc/include/bits/threads_inlines.h b/libc/include/bits/threads_inlines.h new file mode 100644 index 000000000..1130b3a55 --- /dev/null +++ b/libc/include/bits/threads_inlines.h @@ -0,0 +1,207 @@ +/* + * 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 <threads.h> + +#include <errno.h> +#include <sched.h> +#include <stdlib.h> + +#if !defined(__BIONIC_THREADS_INLINE) +#define __BIONIC_THREADS_INLINE static __inline +#endif + +__BEGIN_DECLS + +static __inline int __bionic_thrd_error(int __pthread_code) { + switch (__pthread_code) { + case 0: return 0; + case ENOMEM: return thrd_nomem; + case ETIMEDOUT: return thrd_timedout; + case EBUSY: return thrd_busy; + default: return thrd_error; + } +} + +__BIONIC_THREADS_INLINE void call_once(once_flag* __flag, + void (*__function)(void)) { + pthread_once(__flag, __function); +} + + + +__BIONIC_THREADS_INLINE int cnd_broadcast(cnd_t* __cnd) { + return __bionic_thrd_error(pthread_cond_broadcast(__cnd)); +} + +__BIONIC_THREADS_INLINE void cnd_destroy(cnd_t* __cnd) { + pthread_cond_destroy(__cnd); +} + +__BIONIC_THREADS_INLINE int cnd_init(cnd_t* __cnd) { + return __bionic_thrd_error(pthread_cond_init(__cnd, NULL)); +} + +__BIONIC_THREADS_INLINE int cnd_signal(cnd_t* __cnd) { + return __bionic_thrd_error(pthread_cond_signal(__cnd)); +} + +__BIONIC_THREADS_INLINE int cnd_timedwait(cnd_t* __cnd, + mtx_t* __mtx, + const struct timespec* __timeout) { + return __bionic_thrd_error(pthread_cond_timedwait(__cnd, __mtx, __timeout)); +} + +__BIONIC_THREADS_INLINE int cnd_wait(cnd_t* __cnd, mtx_t* __mtx) { + return __bionic_thrd_error(pthread_cond_wait(__cnd, __mtx)); +} + + + +__BIONIC_THREADS_INLINE void mtx_destroy(mtx_t* __mtx) { + pthread_mutex_destroy(__mtx); +} + +__BIONIC_THREADS_INLINE int mtx_init(mtx_t* __mtx, int __type) { + int __pthread_type = (__type & mtx_recursive) ? PTHREAD_MUTEX_RECURSIVE + : PTHREAD_MUTEX_NORMAL; + __type &= ~mtx_recursive; + if (__type != mtx_plain && __type != mtx_timed) return thrd_error; + + pthread_mutexattr_t __attr; + pthread_mutexattr_init(&__attr); + pthread_mutexattr_settype(&__attr, __pthread_type); + return __bionic_thrd_error(pthread_mutex_init(__mtx, &__attr)); +} + +__BIONIC_THREADS_INLINE int mtx_lock(mtx_t* __mtx) { + return __bionic_thrd_error(pthread_mutex_lock(__mtx)); +} + +__BIONIC_THREADS_INLINE int mtx_timedlock(mtx_t* __mtx, + const struct timespec* __timeout) { + return __bionic_thrd_error(pthread_mutex_timedlock(__mtx, __timeout)); +} + +__BIONIC_THREADS_INLINE int mtx_trylock(mtx_t* __mtx) { + return __bionic_thrd_error(pthread_mutex_trylock(__mtx)); +} + +__BIONIC_THREADS_INLINE int mtx_unlock(mtx_t* __mtx) { + return __bionic_thrd_error(pthread_mutex_unlock(__mtx)); +} + + + +struct __bionic_thrd_data { + thrd_start_t __func; + void* __arg; +}; + +static inline void* __bionic_thrd_trampoline(void* __arg) { + struct __bionic_thrd_data __data = + *__BIONIC_CAST(static_cast, struct __bionic_thrd_data*, __arg); + free(__arg); + int __result = __data.__func(__data.__arg); + return __BIONIC_CAST(reinterpret_cast, void*, + __BIONIC_CAST(static_cast, uintptr_t, __result)); +} + +__BIONIC_THREADS_INLINE int thrd_create(thrd_t* __thrd, + thrd_start_t __func, + void* __arg) { + struct __bionic_thrd_data* __pthread_arg = + __BIONIC_CAST(static_cast, struct __bionic_thrd_data*, + malloc(sizeof(struct __bionic_thrd_data))); + __pthread_arg->__func = __func; + __pthread_arg->__arg = __arg; + int __result = __bionic_thrd_error(pthread_create(__thrd, NULL, + __bionic_thrd_trampoline, + __pthread_arg)); + if (__result != thrd_success) free(__pthread_arg); + return __result; +} + +__BIONIC_THREADS_INLINE thrd_t thrd_current(void) { + return pthread_self(); +} + +__BIONIC_THREADS_INLINE int thrd_detach(thrd_t __thrd) { + return __bionic_thrd_error(pthread_detach(__thrd)); +} + +__BIONIC_THREADS_INLINE int thrd_equal(thrd_t __lhs, thrd_t __rhs) { + return pthread_equal(__lhs, __rhs); +} + +__BIONIC_THREADS_INLINE void thrd_exit(int __result) { + pthread_exit(__BIONIC_CAST(reinterpret_cast, void*, + __BIONIC_CAST(static_cast, uintptr_t, __result))); +} + +__BIONIC_THREADS_INLINE int thrd_join(thrd_t __thrd, int* __result) { + void* __pthread_result; + if (pthread_join(__thrd, &__pthread_result) != 0) return thrd_error; + if (__result) { + *__result = __BIONIC_CAST(reinterpret_cast, intptr_t, __pthread_result); + } + return thrd_success; +} + +__BIONIC_THREADS_INLINE int thrd_sleep(const struct timespec* __duration, + struct timespec* __remaining) { + int __rc = nanosleep(__duration, __remaining); + if (__rc == 0) return 0; + return (errno == EINTR) ? -1 : -2; +} + +__BIONIC_THREADS_INLINE void thrd_yield(void) { + sched_yield(); +} + + + +__BIONIC_THREADS_INLINE int tss_create(tss_t* __key, tss_dtor_t __dtor) { + return __bionic_thrd_error(pthread_key_create(__key, __dtor)); +} + +__BIONIC_THREADS_INLINE void tss_delete(tss_t __key) { + pthread_key_delete(__key); +} + +__BIONIC_THREADS_INLINE void* tss_get(tss_t __key) { + return pthread_getspecific(__key); +} + +__BIONIC_THREADS_INLINE int tss_set(tss_t __key, void* __value) { + return __bionic_thrd_error(pthread_setspecific(__key, __value)); +} + +__END_DECLS diff --git a/libc/include/threads.h b/libc/include/threads.h new file mode 100644 index 000000000..2c43b0b65 --- /dev/null +++ b/libc/include/threads.h @@ -0,0 +1,228 @@ +/* + * 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 + +/** + * @file threads.h + * @brief C11 threads. + */ + +#include <sys/cdefs.h> + +#include <pthread.h> +#include <time.h> + +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT +#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS + +/** The type for a condition variable. */ +typedef pthread_cond_t cnd_t; +/** The type for a thread. */ +typedef pthread_t thrd_t; +/** The type for a thread-specific storage key. */ +typedef pthread_key_t tss_t; +/** The type for a mutex. */ +typedef pthread_mutex_t mtx_t; + +/** The type for a thread-specific storage destructor. */ +typedef void (*tss_dtor_t)(void*); +/** The type of the function passed to thrd_create() to create a new thread. */ +typedef int (*thrd_start_t)(void*); + +/** The type used by call_once(). */ +typedef pthread_once_t once_flag; + +enum { + mtx_plain = 0x1, + mtx_recursive = 0x2, + mtx_timed = 0x4, +}; + +enum { + thrd_success = 0, + thrd_busy = 1, + thrd_error = 2, + thrd_nomem = 3, + thrd_timedout = 4, +}; + +#if !defined(__cplusplus) +#define thread_local _Thread_local +#endif + +__BEGIN_DECLS + +#if __ANDROID_API__ >= __ANDROID_API_R__ +// This file is implemented as static inlines before API level 30. + +/** Uses `__flag` to ensure that `__function` is called exactly once. */ +void call_once(once_flag* __flag, void (*__function)(void)); + + + +/** + * Unblocks all threads blocked on `__cond`. + */ +int cnd_broadcast(cnd_t* __cond); + +/** + * Destroys a condition variable. + */ +void cnd_destroy(cnd_t* __cond); + +/** + * Creates a condition variable. + */ +int cnd_init(cnd_t* __cond); + +/** + * Unblocks one thread blocked on `__cond`. + */ +int cnd_signal(cnd_t* __cond); + +/** + * Unlocks `__mutex` and blocks until `__cond` is signaled or `__timeout` occurs. + */ +int cnd_timedwait(cnd_t* __cond, mtx_t* __mutex, const struct timespec* __timeout); + +/** + * Unlocks `__mutex` and blocks until `__cond` is signaled. + */ +int cnd_wait(cnd_t* __cond, mtx_t* __mutex); + + + +/** + * Destroys a mutex. + */ +void mtx_destroy(mtx_t* __mutex); + +/** + * Creates a mutex. + */ +int mtx_init(mtx_t* __mutex, int __type); + +/** + * Blocks until `__mutex` is acquired. + */ +int mtx_lock(mtx_t* __mutex); + +/** + * Blocks until `__mutex` is acquired or `__timeout` expires. + */ +int mtx_timedlock(mtx_t* __mutex, const struct timespec* __timeout); + +/** + * Acquires `__mutex` or returns `thrd_busy`. + */ +int mtx_trylock(mtx_t* __mutex); + +/** + * Unlocks `__mutex`. + */ +int mtx_unlock(mtx_t* __mutex); + + + +/** + * Creates a new thread running `__function(__arg)`, and sets `*__thrd` to + * the new thread. + */ +int thrd_create(thrd_t* __thrd, thrd_start_t __function, void* __arg); + +/** + * Returns the `thrd_t` corresponding to the caller. + */ +thrd_t thrd_current(void); + +/** + * Tells the OS to automatically dispose of `__thrd` when it exits. + */ +int thrd_detach(thrd_t __thrd); + +/** + * Tests whether two threads are the same thread. + */ +int thrd_equal(thrd_t __lhs, thrd_t __rhs); + +/** + * Terminates the calling thread, setting its result to `__result`. + */ +void thrd_exit(int __result) __noreturn; + +/** + * Blocks until `__thrd` terminates. If `__result` is not null, `*__result` + * is set to the exiting thread's result. + */ +int thrd_join(thrd_t __thrd, int* __result); + +/** + * Blocks the caller for at least `__duration` unless a signal is delivered. + * If a signal causes the sleep to end early and `__remaining` is not null, + * `*__remaining` is set to the time remaining. + * + * Returns 0 on success, or -1 if a signal was delivered. + */ +int thrd_sleep(const struct timespec* __duration, struct timespec* __remaining); + +/** + * Request that other threads should be scheduled. + */ +void thrd_yield(void); + + + +/** + * Creates a thread-specific storage key with the associated destructor (which + * may be null). + */ +int tss_create(tss_t* __key, tss_dtor_t __dtor); + +/** + * Destroys a thread-specific storage key. + */ +void tss_delete(tss_t __key); + +/** + * Returns the value for the current thread held in the thread-specific storage + * identified by `__key`. + */ +void* tss_get(tss_t __key); + +/** + * Sets the current thread's value for the thread-specific storage identified + * by `__key` to `__value`. + */ +int tss_set(tss_t __key, void* __value); + +#endif + +__END_DECLS + +#include <android/legacy_threads_inlines.h> diff --git a/libc/libc.map.txt b/libc/libc.map.txt index 55ca9dcfb..4a734fc20 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -1473,18 +1473,42 @@ LIBC_Q { # introduced=Q malloc_enable; # apex malloc_iterate; # apex - # Used by libmediautils - write_malloc_leak_info; # apex - free_malloc_leak_info; # apex - get_malloc_leak_info; # apex - # Used by libandroid_net android_getaddrinfofornet; # apex - # Used by libandroid_runtime and libmedia + # Used by libandroid_runtime, libmedia and libmediautils android_mallopt; # apex } LIBC_P; +LIBC_R { # introduced=R + global: + call_once; + cnd_broadcast; + cnd_destroy; + cnd_init; + cnd_signal; + cnd_timedwait; + cnd_wait; + mtx_destroy; + mtx_init; + mtx_lock; + mtx_timedlock; + mtx_trylock; + mtx_unlock; + thrd_create; + thrd_current; + thrd_detach; + thrd_equal; + thrd_exit; + thrd_join; + thrd_sleep; + thrd_yield; + tss_create; + tss_delete; + tss_get; + tss_set; +} LIBC_Q; + LIBC_PRIVATE { global: ___Unwind_Backtrace; # arm diff --git a/libc/malloc_hooks/tests/malloc_hooks_tests.cpp b/libc/malloc_hooks/tests/malloc_hooks_tests.cpp index 0d23a6a8f..86e20ea90 100644 --- a/libc/malloc_hooks/tests/malloc_hooks_tests.cpp +++ b/libc/malloc_hooks/tests/malloc_hooks_tests.cpp @@ -38,6 +38,7 @@ #include <gtest/gtest.h> +#include <private/bionic_malloc.h> #include <private/bionic_malloc_dispatch.h> #include <tests/utils.h> @@ -197,19 +198,15 @@ TEST_F(MallocHooksTest, extended_functions) { } TEST_F(MallocHooksTest, DISABLED_extended_functions) { - uint8_t* info = nullptr; - size_t overall_size = 100; - size_t info_size = 200; - size_t total_memory = 300; - size_t backtrace_size = 400; - get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size); - EXPECT_EQ(nullptr, info); - EXPECT_EQ(0U, overall_size); - EXPECT_EQ(0U, info_size); - EXPECT_EQ(0U, total_memory); - EXPECT_EQ(0U, backtrace_size); - - free_malloc_leak_info(info); + android_mallopt_leak_info_t leak_info; + ASSERT_TRUE(android_mallopt(M_GET_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info))); + EXPECT_EQ(nullptr, leak_info.buffer); + EXPECT_EQ(0U, leak_info.overall_size); + EXPECT_EQ(0U, leak_info.info_size); + EXPECT_EQ(0U, leak_info.total_memory); + EXPECT_EQ(0U, leak_info.backtrace_size); + + ASSERT_TRUE(android_mallopt(M_FREE_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info))); malloc_enable(); malloc_disable(); diff --git a/libc/private/bionic_malloc.h b/libc/private/bionic_malloc.h index e8a6f6ef5..9c602eadf 100644 --- a/libc/private/bionic_malloc.h +++ b/libc/private/bionic_malloc.h @@ -30,6 +30,22 @@ #include <stdbool.h> +// Structures for android_mallopt. + +typedef struct { + // Pointer to the buffer allocated by a call to M_GET_MALLOC_LEAK_INFO. + uint8_t* buffer; + // The size of the "info" buffer. + size_t overall_size; + // The size of a single entry. + size_t info_size; + // The sum of all allocations that have been tracked. Does not include + // any heap overhead. + size_t total_memory; + // The maximum number of backtrace entries. + size_t backtrace_size; +} android_mallopt_leak_info_t; + // Opcodes for android_mallopt. enum { @@ -48,6 +64,26 @@ enum { // Called after the zygote forks to indicate this is a child. M_SET_ZYGOTE_CHILD = 4, #define M_SET_ZYGOTE_CHILD M_SET_ZYGOTE_CHILD + + // Options to dump backtraces of allocations. These options only + // work when malloc debug has been enabled. + + // Writes the backtrace information of all current allocations to a file. + // NOTE: arg_size has to be sizeof(FILE*) because FILE is an opaque type. + // arg = FILE* + // arg_size = sizeof(FILE*) + M_WRITE_MALLOC_LEAK_INFO_TO_FILE = 5, +#define M_WRITE_MALLOC_LEAK_INFO_TO_FILE M_WRITE_MALLOC_LEAK_INFO_TO_FILE + // Get information about the backtraces of all + // arg = android_mallopt_leak_info_t* + // arg_size = sizeof(android_mallopt_leak_info_t) + M_GET_MALLOC_LEAK_INFO = 6, +#define M_GET_MALLOC_LEAK_INFO M_GET_MALLOC_LEAK_INFO + // Free the memory allocated and returned by M_GET_MALLOC_LEAK_INFO. + // arg = android_mallopt_leak_info_t* + // arg_size = sizeof(android_mallopt_leak_info_t) + M_FREE_MALLOC_LEAK_INFO = 7, +#define M_FREE_MALLOC_LEAK_INFO M_FREE_MALLOC_LEAK_INFO }; // Manipulates bionic-specific handling of memory allocation APIs such as diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c index bd6ac3db0..692e0c0fc 100644 --- a/libc/stdlib/atexit.c +++ b/libc/stdlib/atexit.c @@ -186,7 +186,10 @@ restart: } _ATEXIT_UNLOCK(); - fflush(NULL); + /* If called via exit(), flush output of all open files. */ + if (dso == NULL) { + fflush(NULL); + } /* BEGIN android-changed: call __unregister_atfork if dso is not null */ if (dso != NULL) { |