diff --git a/src/library_pthread.js b/src/library_pthread.js index 4bc001b758b7a..4670ccecc0617 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -1024,8 +1024,8 @@ var LibraryPThread = { return 0; }, - pthread_detach__sig: 'vi', - pthread_detach: function(thread) { + {{{ USE_LSAN ? 'emscripten_builtin_' : '' }}}pthread_detach__sig: 'vi', + {{{ USE_LSAN ? 'emscripten_builtin_' : '' }}}pthread_detach: function(thread) { if (!thread) { err('pthread_detach attempted on a null thread pointer!'); return ERRNO_CODES.ESRCH; @@ -1043,9 +1043,13 @@ var LibraryPThread = { return wasDetached ? ERRNO_CODES.EINVAL : 0; }, - // C11 threads function. + // C11 thread version. // TODO: remove this in favor or compiling musl/src/thread/pthread_detach.c +#if USE_LSAN + thrd_detach: 'emscripten_builtin_pthread_detach', +#else thrd_detach: 'pthread_detach', +#endif pthread_exit__deps: ['exit'], pthread_exit: function(status) { diff --git a/system/lib/compiler-rt/include/sanitizer/asan_interface.h b/system/lib/compiler-rt/include/sanitizer/asan_interface.h index 6af93aad6512f..792ef9cfaa32b 100644 --- a/system/lib/compiler-rt/include/sanitizer/asan_interface.h +++ b/system/lib/compiler-rt/include/sanitizer/asan_interface.h @@ -188,8 +188,8 @@ const char *__asan_get_report_description(void); /// \param addr Address to locate. /// \param name Buffer to store the variable's name. /// \param name_size Size in bytes of the variable's name buffer. -/// \param region_address [out] Address of the region. -/// \param region_size [out] Size of the region in bytes. +/// \param[out] region_address Address of the region. +/// \param[out] region_size Size of the region in bytes. /// /// \returns Returns the category of the given pointer as a constant string. const char *__asan_locate_address(void *addr, char *name, size_t name_size, @@ -204,7 +204,7 @@ const char *__asan_locate_address(void *addr, char *name, size_t name_size, /// \param addr A heap address. /// \param trace A buffer to store the stack trace. /// \param size Size in bytes of the trace buffer. -/// \param thread_id [out] The thread ID of the address. +/// \param[out] thread_id The thread ID of the address. /// /// \returns Returns the number of stored frames or 0 on error. size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size, @@ -219,7 +219,7 @@ size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size, /// \param addr A heap address. /// \param trace A buffer to store the stack trace. /// \param size Size in bytes of the trace buffer. -/// \param thread_id [out] The thread ID of the address. +/// \param[out] thread_id The thread ID of the address. /// /// \returns Returns the number of stored frames or 0 on error. size_t __asan_get_free_stack(void *addr, void **trace, size_t size, @@ -228,8 +228,8 @@ size_t __asan_get_free_stack(void *addr, void **trace, size_t size, /// Gets the current shadow memory mapping (useful for calling from the /// debugger). /// -/// \param shadow_scale [out] Shadow scale value. -/// \param shadow_offset [out] Offset value. +/// \param[out] shadow_scale Shadow scale value. +/// \param[out] shadow_offset Offset value. void __asan_get_shadow_mapping(size_t *shadow_scale, size_t *shadow_offset); /// This is an internal function that is called to report an error. However, @@ -302,8 +302,8 @@ void *__asan_get_current_fake_stack(void); /// /// \param fake_stack An opaque handler to a fake stack. /// \param addr Address to test. -/// \param beg [out] Beginning of fake frame. -/// \param end [out] End of fake frame. +/// \param[out] beg Beginning of fake frame. +/// \param[out] end End of fake frame. /// \returns Stack address or NULL. void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg, void **end); diff --git a/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h b/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h index f979c6a8f63b1..cd69285b8d4af 100644 --- a/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h +++ b/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h @@ -43,6 +43,9 @@ void __sanitizer_set_report_path(const char *path); // Tell the tools to write their reports to the provided file descriptor // (casted to void *). void __sanitizer_set_report_fd(void *fd); +// Get the current full report file path, if a path was specified by +// an earlier call to __sanitizer_set_report_path. Returns null otherwise. +const char *__sanitizer_get_report_path(); // Notify the tools that the sandbox is going to be turned on. The reserved // parameter will be used in the future to hold a structure with functions @@ -320,7 +323,7 @@ void __sanitizer_print_memory_profile(size_t top_percent, /// signal callback runs during the switch, it will not benefit from stack /// use-after-return detection. /// -/// \param fake_stack_save [out] Fake stack save location. +/// \param[out] fake_stack_save Fake stack save location. /// \param bottom Bottom address of stack. /// \param size Size of stack in bytes. void __sanitizer_start_switch_fiber(void **fake_stack_save, @@ -335,8 +338,8 @@ void __sanitizer_start_switch_fiber(void **fake_stack_save, /// __sanitizer_start_switch_fiber(). /// /// \param fake_stack_save Fake stack save location. -/// \param bottom_old [out] Bottom address of old stack. -/// \param size_old [out] Size of old stack in bytes. +/// \param[out] bottom_old Bottom address of old stack. +/// \param[out] size_old Size of old stack in bytes. void __sanitizer_finish_switch_fiber(void *fake_stack_save, const void **bottom_old, size_t *size_old); diff --git a/system/lib/compiler-rt/include/sanitizer/dfsan_interface.h b/system/lib/compiler-rt/include/sanitizer/dfsan_interface.h index 81546e5df71af..18b2c81a6023c 100644 --- a/system/lib/compiler-rt/include/sanitizer/dfsan_interface.h +++ b/system/lib/compiler-rt/include/sanitizer/dfsan_interface.h @@ -80,9 +80,11 @@ dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc); size_t dfsan_get_label_count(void); /// Flushes the DFSan shadow, i.e. forgets about all labels currently associated -/// with the application memory. Will work only if there are no other -/// threads executing DFSan-instrumented code concurrently. -/// Use this call to start over the taint tracking within the same procces. +/// with the application memory. Use this call to start over the taint tracking +/// within the same process. +/// +/// Note: If another thread is working with tainted data during the flush, that +/// taint could still be written to shadow after the flush. void dfsan_flush(void); /// Sets a callback to be invoked on calls to write(). The callback is invoked diff --git a/system/lib/compiler-rt/include/sanitizer/hwasan_interface.h b/system/lib/compiler-rt/include/sanitizer/hwasan_interface.h index 4c9ad13aa0cb1..14035c05c6353 100644 --- a/system/lib/compiler-rt/include/sanitizer/hwasan_interface.h +++ b/system/lib/compiler-rt/include/sanitizer/hwasan_interface.h @@ -73,6 +73,9 @@ extern "C" { * accessed through the pointer in x, or -1 if the whole range is good. */ intptr_t __hwasan_test_shadow(const volatile void *x, size_t size); + /* Sets the callback function to be called during HWASan error reporting. */ + void __hwasan_set_error_report_callback(void (*callback)(const char *)); + int __sanitizer_posix_memalign(void **memptr, size_t alignment, size_t size); void * __sanitizer_memalign(size_t alignment, size_t size); void * __sanitizer_aligned_alloc(size_t alignment, size_t size); diff --git a/system/lib/compiler-rt/include/sanitizer/linux_syscall_hooks.h b/system/lib/compiler-rt/include/sanitizer/linux_syscall_hooks.h index a1794b71af503..56eae3d40f968 100644 --- a/system/lib/compiler-rt/include/sanitizer/linux_syscall_hooks.h +++ b/system/lib/compiler-rt/include/sanitizer/linux_syscall_hooks.h @@ -1845,6 +1845,10 @@ #define __sanitizer_syscall_post_rt_sigaction(res, signum, act, oldact, sz) \ __sanitizer_syscall_post_impl_rt_sigaction(res, (long)signum, (long)act, \ (long)oldact, (long)sz) +#define __sanitizer_syscall_pre_sigaltstack(ss, oss) \ + __sanitizer_syscall_pre_impl_sigaltstack((long)ss, (long)oss) +#define __sanitizer_syscall_post_sigaltstack(res, ss, oss) \ + __sanitizer_syscall_post_impl_sigaltstack(res, (long)ss, (long)oss) // And now a few syscalls we don't handle yet. #define __sanitizer_syscall_pre_afs_syscall(...) @@ -1912,7 +1916,6 @@ #define __sanitizer_syscall_pre_setreuid32(...) #define __sanitizer_syscall_pre_set_thread_area(...) #define __sanitizer_syscall_pre_setuid32(...) -#define __sanitizer_syscall_pre_sigaltstack(...) #define __sanitizer_syscall_pre_sigreturn(...) #define __sanitizer_syscall_pre_sigsuspend(...) #define __sanitizer_syscall_pre_stty(...) @@ -1992,7 +1995,6 @@ #define __sanitizer_syscall_post_setreuid32(res, ...) #define __sanitizer_syscall_post_set_thread_area(res, ...) #define __sanitizer_syscall_post_setuid32(res, ...) -#define __sanitizer_syscall_post_sigaltstack(res, ...) #define __sanitizer_syscall_post_sigreturn(res, ...) #define __sanitizer_syscall_post_sigsuspend(res, ...) #define __sanitizer_syscall_post_stty(res, ...) @@ -3075,6 +3077,8 @@ void __sanitizer_syscall_pre_impl_rt_sigaction(long signum, long act, long oldact, long sz); void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act, long oldact, long sz); +void __sanitizer_syscall_pre_impl_sigaltstack(long ss, long oss); +void __sanitizer_syscall_post_impl_sigaltstack(long res, long ss, long oss); #ifdef __cplusplus } // extern "C" #endif diff --git a/system/lib/compiler-rt/include/sanitizer/memprof_interface.h b/system/lib/compiler-rt/include/sanitizer/memprof_interface.h new file mode 100644 index 0000000000000..76031de4014c0 --- /dev/null +++ b/system/lib/compiler-rt/include/sanitizer/memprof_interface.h @@ -0,0 +1,65 @@ +//===-- sanitizer/memprof_interface.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemProfiler (MemProf). +// +// Public interface header. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_MEMPROF_INTERFACE_H +#define SANITIZER_MEMPROF_INTERFACE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif +/// Records access to a memory region ([addr, addr+size)). +/// +/// This memory must be previously allocated by your program. +/// +/// \param addr Start of memory region. +/// \param size Size of memory region. +void __memprof_record_access_range(void const volatile *addr, size_t size); + +/// Records access to a memory address addr. +/// +/// This memory must be previously allocated by your program. +/// +/// \param addr Accessed memory address +void __memprof_record_access(void const volatile *addr); + +/// User-provided callback on MemProf errors. +/// +/// You can provide a function that would be called immediately when MemProf +/// detects an error. This is useful in cases when MemProf detects an error but +/// your program crashes before the MemProf report is printed. +void __memprof_on_error(void); + +/// Prints accumulated statistics to stderr (useful for calling from the +/// debugger). +void __memprof_print_accumulated_stats(void); + +/// User-provided default option settings. +/// +/// You can provide your own implementation of this function to return a string +/// containing MemProf runtime options (for example, +/// verbosity=1:print_stats=1). +/// +/// \returns Default options string. +const char *__memprof_default_options(void); + +/// Prints the memory profile to the current profile file. +/// +/// \returns 0 on success. +int __memprof_profile_dump(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // SANITIZER_MEMPROF_INTERFACE_H diff --git a/system/lib/compiler-rt/include/sanitizer/msan_interface.h b/system/lib/compiler-rt/include/sanitizer/msan_interface.h index d40c556a46d93..eeb39fbed8b49 100644 --- a/system/lib/compiler-rt/include/sanitizer/msan_interface.h +++ b/system/lib/compiler-rt/include/sanitizer/msan_interface.h @@ -114,6 +114,9 @@ extern "C" { call to __msan_scoped_disable_interceptor_checks. */ void __msan_scoped_enable_interceptor_checks(void); + void __msan_start_switch_fiber(const void *bottom, size_t size); + void __msan_finish_switch_fiber(const void **bottom_old, size_t *size_old); + #ifdef __cplusplus } // extern "C" #endif diff --git a/system/lib/compiler-rt/include/sanitizer/netbsd_syscall_hooks.h b/system/lib/compiler-rt/include/sanitizer/netbsd_syscall_hooks.h index 370da0ea72ed8..f661152ccbac7 100644 --- a/system/lib/compiler-rt/include/sanitizer/netbsd_syscall_hooks.h +++ b/system/lib/compiler-rt/include/sanitizer/netbsd_syscall_hooks.h @@ -20,8 +20,8 @@ // DO NOT EDIT! THIS FILE HAS BEEN GENERATED! // // Generated with: generate_netbsd_syscalls.awk -// Generated date: 2019-12-24 -// Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp +// Generated date: 2020-09-10 +// Generated from: syscalls.master,v 1.306 2020/08/14 00:53:16 riastradh Exp // //===----------------------------------------------------------------------===// #ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H @@ -474,7 +474,12 @@ __sanitizer_syscall_pre_impl_dup2((long long)(from), (long long)(to)) #define __sanitizer_syscall_post_dup2(res, from, to) \ __sanitizer_syscall_post_impl_dup2(res, (long long)(from), (long long)(to)) -/* syscall 91 has been skipped */ +#define __sanitizer_syscall_pre_getrandom(buf, buflen, flags) \ + __sanitizer_syscall_pre_impl_getrandom( \ + (long long)(buf), (long long)(buflen), (long long)(flags)) +#define __sanitizer_syscall_post_getrandom(res, buf, buflen, flags) \ + __sanitizer_syscall_post_impl_getrandom( \ + res, (long long)(buf), (long long)(buflen), (long long)(flags)) #define __sanitizer_syscall_pre_fcntl(fd, cmd, arg) \ __sanitizer_syscall_pre_impl_fcntl((long long)(fd), (long long)(cmd), \ (long long)(arg)) @@ -849,9 +854,31 @@ #define __sanitizer_syscall_post_sysarch(res, op, parms) \ __sanitizer_syscall_post_impl_sysarch(res, (long long)(op), \ (long long)(parms)) -/* syscall 166 has been skipped */ -/* syscall 167 has been skipped */ -/* syscall 168 has been skipped */ +#define __sanitizer_syscall_pre___futex(uaddr, op, val, timeout, uaddr2, val2, \ + val3) \ + __sanitizer_syscall_pre_impl___futex((long long)(uaddr), (long long)(op), \ + (long long)(val), (long long)(timeout), \ + (long long)(uaddr2), (long long)(val2), \ + (long long)(val3)) +#define __sanitizer_syscall_post___futex(res, uaddr, op, val, timeout, uaddr2, \ + val2, val3) \ + __sanitizer_syscall_post_impl___futex( \ + res, (long long)(uaddr), (long long)(op), (long long)(val), \ + (long long)(timeout), (long long)(uaddr2), (long long)(val2), \ + (long long)(val3)) +#define __sanitizer_syscall_pre___futex_set_robust_list(head, len) \ + __sanitizer_syscall_pre_impl___futex_set_robust_list((long long)(head), \ + (long long)(len)) +#define __sanitizer_syscall_post___futex_set_robust_list(res, head, len) \ + __sanitizer_syscall_post_impl___futex_set_robust_list( \ + res, (long long)(head), (long long)(len)) +#define __sanitizer_syscall_pre___futex_get_robust_list(lwpid, headp, lenp) \ + __sanitizer_syscall_pre_impl___futex_get_robust_list( \ + (long long)(lwpid), (long long)(headp), (long long)(lenp)) +#define __sanitizer_syscall_post___futex_get_robust_list(res, lwpid, headp, \ + lenp) \ + __sanitizer_syscall_post_impl___futex_get_robust_list( \ + res, (long long)(lwpid), (long long)(headp), (long long)(lenp)) #if !defined(_LP64) #define __sanitizer_syscall_pre_compat_10_osemsys(which, a2, a3, a4, a5) \ __sanitizer_syscall_pre_impl_compat_10_osemsys( \ @@ -2731,6 +2758,83 @@ __sanitizer_syscall_post_impl___fhstatvfs190( \ res, (long long)(fhp), (long long)(fh_size), (long long)(buf), \ (long long)(flags)) +#define __sanitizer_syscall_pre___acl_get_link(path, type, aclp) \ + __sanitizer_syscall_pre_impl___acl_get_link( \ + (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_post___acl_get_link(res, path, type, aclp) \ + __sanitizer_syscall_post_impl___acl_get_link( \ + res, (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_pre___acl_set_link(path, type, aclp) \ + __sanitizer_syscall_pre_impl___acl_set_link( \ + (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_post___acl_set_link(res, path, type, aclp) \ + __sanitizer_syscall_post_impl___acl_set_link( \ + res, (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_pre___acl_delete_link(path, type) \ + __sanitizer_syscall_pre_impl___acl_delete_link((long long)(path), \ + (long long)(type)) +#define __sanitizer_syscall_post___acl_delete_link(res, path, type) \ + __sanitizer_syscall_post_impl___acl_delete_link(res, (long long)(path), \ + (long long)(type)) +#define __sanitizer_syscall_pre___acl_aclcheck_link(path, type, aclp) \ + __sanitizer_syscall_pre_impl___acl_aclcheck_link( \ + (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_post___acl_aclcheck_link(res, path, type, aclp) \ + __sanitizer_syscall_post_impl___acl_aclcheck_link( \ + res, (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_pre___acl_get_file(path, type, aclp) \ + __sanitizer_syscall_pre_impl___acl_get_file( \ + (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_post___acl_get_file(res, path, type, aclp) \ + __sanitizer_syscall_post_impl___acl_get_file( \ + res, (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_pre___acl_set_file(path, type, aclp) \ + __sanitizer_syscall_pre_impl___acl_set_file( \ + (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_post___acl_set_file(res, path, type, aclp) \ + __sanitizer_syscall_post_impl___acl_set_file( \ + res, (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_pre___acl_get_fd(filedes, type, aclp) \ + __sanitizer_syscall_pre_impl___acl_get_fd( \ + (long long)(filedes), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_post___acl_get_fd(res, filedes, type, aclp) \ + __sanitizer_syscall_post_impl___acl_get_fd( \ + res, (long long)(filedes), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_pre___acl_set_fd(filedes, type, aclp) \ + __sanitizer_syscall_pre_impl___acl_set_fd( \ + (long long)(filedes), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_post___acl_set_fd(res, filedes, type, aclp) \ + __sanitizer_syscall_post_impl___acl_set_fd( \ + res, (long long)(filedes), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_pre___acl_delete_file(path, type) \ + __sanitizer_syscall_pre_impl___acl_delete_file((long long)(path), \ + (long long)(type)) +#define __sanitizer_syscall_post___acl_delete_file(res, path, type) \ + __sanitizer_syscall_post_impl___acl_delete_file(res, (long long)(path), \ + (long long)(type)) +#define __sanitizer_syscall_pre___acl_delete_fd(filedes, type) \ + __sanitizer_syscall_pre_impl___acl_delete_fd((long long)(filedes), \ + (long long)(type)) +#define __sanitizer_syscall_post___acl_delete_fd(res, filedes, type) \ + __sanitizer_syscall_post_impl___acl_delete_fd(res, (long long)(filedes), \ + (long long)(type)) +#define __sanitizer_syscall_pre___acl_aclcheck_file(path, type, aclp) \ + __sanitizer_syscall_pre_impl___acl_aclcheck_file( \ + (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_post___acl_aclcheck_file(res, path, type, aclp) \ + __sanitizer_syscall_post_impl___acl_aclcheck_file( \ + res, (long long)(path), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_pre___acl_aclcheck_fd(filedes, type, aclp) \ + __sanitizer_syscall_pre_impl___acl_aclcheck_fd( \ + (long long)(filedes), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_post___acl_aclcheck_fd(res, filedes, type, aclp) \ + __sanitizer_syscall_post_impl___acl_aclcheck_fd( \ + res, (long long)(filedes), (long long)(type), (long long)(aclp)) +#define __sanitizer_syscall_pre_lpathconf(path, name) \ + __sanitizer_syscall_pre_impl_lpathconf((long long)(path), (long long)(name)) +#define __sanitizer_syscall_post_lpathconf(res, path, name) \ + __sanitizer_syscall_post_impl_lpathconf(res, (long long)(path), \ + (long long)(name)) /* Compat with older releases */ #define __sanitizer_syscall_pre_getvfsstat \ @@ -3088,7 +3192,10 @@ void __sanitizer_syscall_post_impl_compat_43_ogetdtablesize(long long res); void __sanitizer_syscall_pre_impl_dup2(long long from, long long to); void __sanitizer_syscall_post_impl_dup2(long long res, long long from, long long to); -/* syscall 91 has been skipped */ +void __sanitizer_syscall_pre_impl_getrandom(long long buf, long long buflen, + long long flags); +void __sanitizer_syscall_post_impl_getrandom(long long res, long long buf, + long long buflen, long long flags); void __sanitizer_syscall_pre_impl_fcntl(long long fd, long long cmd, long long arg); void __sanitizer_syscall_post_impl_fcntl(long long res, long long fd, @@ -3380,9 +3487,26 @@ void __sanitizer_syscall_post_impl_compat_09_ouname(long long res, void __sanitizer_syscall_pre_impl_sysarch(long long op, long long parms); void __sanitizer_syscall_post_impl_sysarch(long long res, long long op, long long parms); -/* syscall 166 has been skipped */ -/* syscall 167 has been skipped */ -/* syscall 168 has been skipped */ +void __sanitizer_syscall_pre_impl___futex(long long uaddr, long long op, + long long val, long long timeout, + long long uaddr2, long long val2, + long long val3); +void __sanitizer_syscall_post_impl___futex(long long res, long long uaddr, + long long op, long long val, + long long timeout, long long uaddr2, + long long val2, long long val3); +void __sanitizer_syscall_pre_impl___futex_set_robust_list(long long head, + long long len); +void __sanitizer_syscall_post_impl___futex_set_robust_list(long long res, + long long head, + long long len); +void __sanitizer_syscall_pre_impl___futex_get_robust_list(long long lwpid, + long long headp, + long long lenp); +void __sanitizer_syscall_post_impl___futex_get_robust_list(long long res, + long long lwpid, + long long headp, + long long lenp); #if !defined(_LP64) void __sanitizer_syscall_pre_impl_compat_10_osemsys(long long which, long long a2, long long a3, @@ -4802,6 +4926,75 @@ void __sanitizer_syscall_post_impl___fhstatvfs190(long long res, long long fhp, long long fh_size, long long buf, long long flags); +void __sanitizer_syscall_pre_impl___acl_get_link(long long path, long long type, + long long aclp); +void __sanitizer_syscall_post_impl___acl_get_link(long long res, long long path, + long long type, + long long aclp); +void __sanitizer_syscall_pre_impl___acl_set_link(long long path, long long type, + long long aclp); +void __sanitizer_syscall_post_impl___acl_set_link(long long res, long long path, + long long type, + long long aclp); +void __sanitizer_syscall_pre_impl___acl_delete_link(long long path, + long long type); +void __sanitizer_syscall_post_impl___acl_delete_link(long long res, + long long path, + long long type); +void __sanitizer_syscall_pre_impl___acl_aclcheck_link(long long path, + long long type, + long long aclp); +void __sanitizer_syscall_post_impl___acl_aclcheck_link(long long res, + long long path, + long long type, + long long aclp); +void __sanitizer_syscall_pre_impl___acl_get_file(long long path, long long type, + long long aclp); +void __sanitizer_syscall_post_impl___acl_get_file(long long res, long long path, + long long type, + long long aclp); +void __sanitizer_syscall_pre_impl___acl_set_file(long long path, long long type, + long long aclp); +void __sanitizer_syscall_post_impl___acl_set_file(long long res, long long path, + long long type, + long long aclp); +void __sanitizer_syscall_pre_impl___acl_get_fd(long long filedes, + long long type, long long aclp); +void __sanitizer_syscall_post_impl___acl_get_fd(long long res, + long long filedes, + long long type, long long aclp); +void __sanitizer_syscall_pre_impl___acl_set_fd(long long filedes, + long long type, long long aclp); +void __sanitizer_syscall_post_impl___acl_set_fd(long long res, + long long filedes, + long long type, long long aclp); +void __sanitizer_syscall_pre_impl___acl_delete_file(long long path, + long long type); +void __sanitizer_syscall_post_impl___acl_delete_file(long long res, + long long path, + long long type); +void __sanitizer_syscall_pre_impl___acl_delete_fd(long long filedes, + long long type); +void __sanitizer_syscall_post_impl___acl_delete_fd(long long res, + long long filedes, + long long type); +void __sanitizer_syscall_pre_impl___acl_aclcheck_file(long long path, + long long type, + long long aclp); +void __sanitizer_syscall_post_impl___acl_aclcheck_file(long long res, + long long path, + long long type, + long long aclp); +void __sanitizer_syscall_pre_impl___acl_aclcheck_fd(long long filedes, + long long type, + long long aclp); +void __sanitizer_syscall_post_impl___acl_aclcheck_fd(long long res, + long long filedes, + long long type, + long long aclp); +void __sanitizer_syscall_pre_impl_lpathconf(long long path, long long name); +void __sanitizer_syscall_post_impl_lpathconf(long long res, long long path, + long long name); #ifdef __cplusplus } // extern "C" diff --git a/system/lib/compiler-rt/include/sanitizer/tsan_interface.h b/system/lib/compiler-rt/include/sanitizer/tsan_interface.h index 011b23350cac3..96b8ad58541cb 100644 --- a/system/lib/compiler-rt/include/sanitizer/tsan_interface.h +++ b/system/lib/compiler-rt/include/sanitizer/tsan_interface.h @@ -38,34 +38,34 @@ void __tsan_release(void *addr); // Mutex has static storage duration and no-op constructor and destructor. // This effectively makes tsan ignore destroy annotation. -const unsigned __tsan_mutex_linker_init = 1 << 0; +static const unsigned __tsan_mutex_linker_init = 1 << 0; // Mutex is write reentrant. -const unsigned __tsan_mutex_write_reentrant = 1 << 1; +static const unsigned __tsan_mutex_write_reentrant = 1 << 1; // Mutex is read reentrant. -const unsigned __tsan_mutex_read_reentrant = 1 << 2; +static const unsigned __tsan_mutex_read_reentrant = 1 << 2; // Mutex does not have static storage duration, and must not be used after // its destructor runs. The opposite of __tsan_mutex_linker_init. // If this flag is passed to __tsan_mutex_destroy, then the destruction // is ignored unless this flag was previously set on the mutex. -const unsigned __tsan_mutex_not_static = 1 << 8; +static const unsigned __tsan_mutex_not_static = 1 << 8; // Mutex operation flags: // Denotes read lock operation. -const unsigned __tsan_mutex_read_lock = 1 << 3; +static const unsigned __tsan_mutex_read_lock = 1 << 3; // Denotes try lock operation. -const unsigned __tsan_mutex_try_lock = 1 << 4; +static const unsigned __tsan_mutex_try_lock = 1 << 4; // Denotes that a try lock operation has failed to acquire the mutex. -const unsigned __tsan_mutex_try_lock_failed = 1 << 5; +static const unsigned __tsan_mutex_try_lock_failed = 1 << 5; // Denotes that the lock operation acquires multiple recursion levels. // Number of levels is passed in recursion parameter. // This is useful for annotation of e.g. Java builtin monitors, // for which wait operation releases all recursive acquisitions of the mutex. -const unsigned __tsan_mutex_recursive_lock = 1 << 6; +static const unsigned __tsan_mutex_recursive_lock = 1 << 6; // Denotes that the unlock operation releases all recursion levels. // Number of released levels is returned and later must be passed to // the corresponding __tsan_mutex_post_lock annotation. -const unsigned __tsan_mutex_recursive_unlock = 1 << 7; +static const unsigned __tsan_mutex_recursive_unlock = 1 << 7; // Annotate creation of a mutex. // Supported flags: mutex creation flags. @@ -152,7 +152,7 @@ void __tsan_set_fiber_name(void *fiber, const char *name); // Flags for __tsan_switch_to_fiber: // Do not establish a happens-before relation between fibers -const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0; +static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0; #ifdef __cplusplus } // extern "C" diff --git a/system/lib/compiler-rt/lib/asan/asan_allocator.cpp b/system/lib/compiler-rt/lib/asan/asan_allocator.cpp index 65c51fbafdd0c..cd97b37652f8b 100644 --- a/system/lib/compiler-rt/lib/asan/asan_allocator.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_allocator.cpp @@ -15,20 +15,21 @@ //===----------------------------------------------------------------------===// #include "asan_allocator.h" + #include "asan_mapping.h" #include "asan_poisoning.h" #include "asan_report.h" #include "asan_stack.h" #include "asan_thread.h" +#include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_list.h" -#include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_quarantine.h" -#include "lsan/lsan_common.h" +#include "sanitizer_common/sanitizer_stackdepot.h" namespace __asan { @@ -50,6 +51,22 @@ static u32 RZSize2Log(u32 rz_size) { static AsanAllocator &get_allocator(); +static void AtomicContextStore(volatile atomic_uint64_t *atomic_context, + u32 tid, u32 stack) { + u64 context = tid; + context <<= 32; + context += stack; + atomic_store(atomic_context, context, memory_order_relaxed); +} + +static void AtomicContextLoad(const volatile atomic_uint64_t *atomic_context, + u32 &tid, u32 &stack) { + u64 context = atomic_load(atomic_context, memory_order_relaxed); + stack = context; + context >>= 32; + tid = context; +} + // The memory chunk allocated from the underlying allocator looks like this: // L L L L L L H H U U U U U U R R // L -- left redzone words (0 or more bytes) @@ -67,32 +84,59 @@ static AsanAllocator &get_allocator(); // ---------------------| // M -- magic value kAllocBegMagic // B -- address of ChunkHeader pointing to the first 'H' -static const uptr kAllocBegMagic = 0xCC6E96B9; - -struct ChunkHeader { - // 1-st 8 bytes. - u32 chunk_state : 8; // Must be first. - u32 alloc_tid : 24; - - u32 free_tid : 24; - u32 from_memalign : 1; - u32 alloc_type : 2; - u32 rz_log : 3; - u32 lsan_tag : 2; - // 2-nd 8 bytes - // This field is used for small sizes. For large sizes it is equal to - // SizeClassMap::kMaxSize and the actual size is stored in the - // SecondaryAllocator's metadata. - u32 user_requested_size : 29; + +class ChunkHeader { + public: + atomic_uint8_t chunk_state; + u8 alloc_type : 2; + u8 lsan_tag : 2; + // align < 8 -> 0 // else -> log2(min(align, 512)) - 2 - u32 user_requested_alignment_log : 3; - u32 alloc_context_id; + u8 user_requested_alignment_log : 3; + + private: + u16 user_requested_size_hi; + u32 user_requested_size_lo; + atomic_uint64_t alloc_context_id; + + public: + uptr UsedSize() const { + uptr R = user_requested_size_lo; + if (sizeof(uptr) > sizeof(user_requested_size_lo)) + R += (uptr)user_requested_size_hi << (8 * sizeof(user_requested_size_lo)); + return R; + } + + void SetUsedSize(uptr size) { + user_requested_size_lo = size; + if (sizeof(uptr) > sizeof(user_requested_size_lo)) { + size >>= (8 * sizeof(user_requested_size_lo)); + user_requested_size_hi = size; + CHECK_EQ(user_requested_size_hi, size); + } + } + + void SetAllocContext(u32 tid, u32 stack) { + AtomicContextStore(&alloc_context_id, tid, stack); + } + + void GetAllocContext(u32 &tid, u32 &stack) const { + AtomicContextLoad(&alloc_context_id, tid, stack); + } }; -struct ChunkBase : ChunkHeader { - // Header2, intersects with user memory. - u32 free_context_id; +class ChunkBase : public ChunkHeader { + atomic_uint64_t free_context_id; + + public: + void SetFreeContext(u32 tid, u32 stack) { + AtomicContextStore(&free_context_id, tid, stack); + } + + void GetFreeContext(u32 &tid, u32 &stack) const { + AtomicContextLoad(&free_context_id, tid, stack); + } }; static const uptr kChunkHeaderSize = sizeof(ChunkHeader); @@ -100,35 +144,50 @@ static const uptr kChunkHeader2Size = sizeof(ChunkBase) - kChunkHeaderSize; COMPILER_CHECK(kChunkHeaderSize == 16); COMPILER_CHECK(kChunkHeader2Size <= 16); -// Every chunk of memory allocated by this allocator can be in one of 3 states: -// CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated. -// CHUNK_ALLOCATED: the chunk is allocated and not yet freed. -// CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone. enum { - CHUNK_AVAILABLE = 0, // 0 is the default value even if we didn't set it. - CHUNK_ALLOCATED = 2, - CHUNK_QUARANTINE = 3 + // Either just allocated by underlying allocator, but AsanChunk is not yet + // ready, or almost returned to undelying allocator and AsanChunk is already + // meaningless. + CHUNK_INVALID = 0, + // The chunk is allocated and not yet freed. + CHUNK_ALLOCATED = 2, + // The chunk was freed and put into quarantine zone. + CHUNK_QUARANTINE = 3, }; -struct AsanChunk: ChunkBase { +class AsanChunk : public ChunkBase { + public: uptr Beg() { return reinterpret_cast(this) + kChunkHeaderSize; } - uptr UsedSize(bool locked_version = false) { - if (user_requested_size != SizeClassMap::kMaxSize) - return user_requested_size; - return *reinterpret_cast( - get_allocator().GetMetaData(AllocBeg(locked_version))); + bool AddrIsInside(uptr addr) { + return (addr >= Beg()) && (addr < Beg() + UsedSize()); } - void *AllocBeg(bool locked_version = false) { - if (from_memalign) { - if (locked_version) - return get_allocator().GetBlockBeginFastLocked( - reinterpret_cast(this)); - return get_allocator().GetBlockBegin(reinterpret_cast(this)); - } - return reinterpret_cast(Beg() - RZLog2Size(rz_log)); +}; + +class LargeChunkHeader { + static constexpr uptr kAllocBegMagic = + FIRST_32_SECOND_64(0xCC6E96B9, 0xCC6E96B9CC6E96B9ULL); + atomic_uintptr_t magic; + AsanChunk *chunk_header; + + public: + AsanChunk *Get() const { + return atomic_load(&magic, memory_order_acquire) == kAllocBegMagic + ? chunk_header + : nullptr; } - bool AddrIsInside(uptr addr, bool locked_version = false) { - return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version)); + + void Set(AsanChunk *p) { + if (p) { + chunk_header = p; + atomic_store(&magic, kAllocBegMagic, memory_order_release); + return; + } + + uptr old = kAllocBegMagic; + if (!atomic_compare_exchange_strong(&magic, &old, 0, + memory_order_release)) { + CHECK_EQ(old, kAllocBegMagic); + } } }; @@ -139,23 +198,23 @@ struct QuarantineCallback { } void Recycle(AsanChunk *m) { - CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); - atomic_store((atomic_uint8_t*)m, CHUNK_AVAILABLE, memory_order_relaxed); - CHECK_NE(m->alloc_tid, kInvalidTid); - CHECK_NE(m->free_tid, kInvalidTid); - PoisonShadow(m->Beg(), - RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), - kAsanHeapLeftRedzoneMagic); - void *p = reinterpret_cast(m->AllocBeg()); + void *p = get_allocator().GetBlockBegin(m); if (p != m) { - uptr *alloc_magic = reinterpret_cast(p); - CHECK_EQ(alloc_magic[0], kAllocBegMagic); // Clear the magic value, as allocator internals may overwrite the // contents of deallocated chunk, confusing GetAsanChunk lookup. - alloc_magic[0] = 0; - CHECK_EQ(alloc_magic[1], reinterpret_cast(m)); + reinterpret_cast(p)->Set(nullptr); } + u8 old_chunk_state = CHUNK_QUARANTINE; + if (!atomic_compare_exchange_strong(&m->chunk_state, &old_chunk_state, + CHUNK_INVALID, memory_order_acquire)) { + CHECK_EQ(old_chunk_state, CHUNK_QUARANTINE); + } + + PoisonShadow(m->Beg(), + RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), + kAsanHeapLeftRedzoneMagic); + // Statistics. AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.real_frees++; @@ -299,23 +358,26 @@ struct Allocator { // This could be a user-facing chunk (with redzones), or some internal // housekeeping chunk, like TransferBatch. Start by assuming the former. AsanChunk *ac = GetAsanChunk((void *)chunk); - uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)ac); - uptr beg = ac->Beg(); - uptr end = ac->Beg() + ac->UsedSize(true); - uptr chunk_end = chunk + allocated_size; - if (chunk < beg && beg < end && end <= chunk_end && - ac->chunk_state == CHUNK_ALLOCATED) { - // Looks like a valid AsanChunk in use, poison redzones only. - PoisonShadow(chunk, beg - chunk, kAsanHeapLeftRedzoneMagic); - uptr end_aligned_down = RoundDownTo(end, SHADOW_GRANULARITY); - FastPoisonShadowPartialRightRedzone( - end_aligned_down, end - end_aligned_down, - chunk_end - end_aligned_down, kAsanHeapLeftRedzoneMagic); - } else { - // This is either not an AsanChunk or freed or quarantined AsanChunk. - // In either case, poison everything. - PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic); + uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)chunk); + if (ac && atomic_load(&ac->chunk_state, memory_order_acquire) == + CHUNK_ALLOCATED) { + uptr beg = ac->Beg(); + uptr end = ac->Beg() + ac->UsedSize(); + uptr chunk_end = chunk + allocated_size; + if (chunk < beg && beg < end && end <= chunk_end) { + // Looks like a valid AsanChunk in use, poison redzones only. + PoisonShadow(chunk, beg - chunk, kAsanHeapLeftRedzoneMagic); + uptr end_aligned_down = RoundDownTo(end, SHADOW_GRANULARITY); + FastPoisonShadowPartialRightRedzone( + end_aligned_down, end - end_aligned_down, + chunk_end - end_aligned_down, kAsanHeapLeftRedzoneMagic); + return; + } } + + // This is either not an AsanChunk or freed or quarantined AsanChunk. + // In either case, poison everything. + PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic); } void ReInitialize(const AllocatorOptions &options) { @@ -348,17 +410,18 @@ struct Allocator { // -------------------- Helper methods. ------------------------- uptr ComputeRZLog(uptr user_requested_size) { - u32 rz_log = - user_requested_size <= 64 - 16 ? 0 : - user_requested_size <= 128 - 32 ? 1 : - user_requested_size <= 512 - 64 ? 2 : - user_requested_size <= 4096 - 128 ? 3 : - user_requested_size <= (1 << 14) - 256 ? 4 : - user_requested_size <= (1 << 15) - 512 ? 5 : - user_requested_size <= (1 << 16) - 1024 ? 6 : 7; - u32 min_rz = atomic_load(&min_redzone, memory_order_acquire); - u32 max_rz = atomic_load(&max_redzone, memory_order_acquire); - return Min(Max(rz_log, RZSize2Log(min_rz)), RZSize2Log(max_rz)); + u32 rz_log = user_requested_size <= 64 - 16 ? 0 + : user_requested_size <= 128 - 32 ? 1 + : user_requested_size <= 512 - 64 ? 2 + : user_requested_size <= 4096 - 128 ? 3 + : user_requested_size <= (1 << 14) - 256 ? 4 + : user_requested_size <= (1 << 15) - 512 ? 5 + : user_requested_size <= (1 << 16) - 1024 ? 6 + : 7; + u32 hdr_log = RZSize2Log(RoundUpToPowerOfTwo(sizeof(ChunkHeader))); + u32 min_log = RZSize2Log(atomic_load(&min_redzone, memory_order_acquire)); + u32 max_log = RZSize2Log(atomic_load(&max_redzone, memory_order_acquire)); + return Min(Max(rz_log, Max(min_log, hdr_log)), Max(max_log, hdr_log)); } static uptr ComputeUserRequestedAlignmentLog(uptr user_requested_alignment) { @@ -378,16 +441,23 @@ struct Allocator { // We have an address between two chunks, and we want to report just one. AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk, AsanChunk *right_chunk) { + if (!left_chunk) + return right_chunk; + if (!right_chunk) + return left_chunk; // Prefer an allocated chunk over freed chunk and freed chunk // over available chunk. - if (left_chunk->chunk_state != right_chunk->chunk_state) { - if (left_chunk->chunk_state == CHUNK_ALLOCATED) + u8 left_state = atomic_load(&left_chunk->chunk_state, memory_order_relaxed); + u8 right_state = + atomic_load(&right_chunk->chunk_state, memory_order_relaxed); + if (left_state != right_state) { + if (left_state == CHUNK_ALLOCATED) return left_chunk; - if (right_chunk->chunk_state == CHUNK_ALLOCATED) + if (right_state == CHUNK_ALLOCATED) return right_chunk; - if (left_chunk->chunk_state == CHUNK_QUARANTINE) + if (left_state == CHUNK_QUARANTINE) return left_chunk; - if (right_chunk->chunk_state == CHUNK_QUARANTINE) + if (right_state == CHUNK_QUARANTINE) return right_chunk; } // Same chunk_state: choose based on offset. @@ -402,10 +472,11 @@ struct Allocator { bool UpdateAllocationStack(uptr addr, BufferedStackTrace *stack) { AsanChunk *m = GetAsanChunkByAddr(addr); if (!m) return false; - if (m->chunk_state != CHUNK_ALLOCATED) return false; + if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED) + return false; if (m->Beg() != addr) return false; - atomic_store((atomic_uint32_t *)&m->alloc_context_id, StackDepotPut(*stack), - memory_order_relaxed); + AsanThread *t = GetCurrentThread(); + m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack)); return true; } @@ -442,13 +513,10 @@ struct Allocator { uptr needed_size = rounded_size + rz_size; if (alignment > min_alignment) needed_size += alignment; - bool using_primary_allocator = true; // If we are allocating from the secondary allocator, there will be no // automatic right redzone, so add the right redzone manually. - if (!PrimaryAllocator::CanAllocate(needed_size, alignment)) { + if (!PrimaryAllocator::CanAllocate(needed_size, alignment)) needed_size += rz_size; - using_primary_allocator = false; - } CHECK(IsAligned(needed_size, min_alignment)); if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize || size > max_user_defined_malloc_size) { @@ -490,8 +558,7 @@ struct Allocator { uptr alloc_beg = reinterpret_cast(allocated); uptr alloc_end = alloc_beg + needed_size; - uptr beg_plus_redzone = alloc_beg + rz_size; - uptr user_beg = beg_plus_redzone; + uptr user_beg = alloc_beg + rz_size; if (!IsAligned(user_beg, alignment)) user_beg = RoundUpTo(user_beg, alignment); uptr user_end = user_beg + size; @@ -499,31 +566,11 @@ struct Allocator { uptr chunk_beg = user_beg - kChunkHeaderSize; AsanChunk *m = reinterpret_cast(chunk_beg); m->alloc_type = alloc_type; - m->rz_log = rz_log; - u32 alloc_tid = t ? t->tid() : 0; - m->alloc_tid = alloc_tid; - CHECK_EQ(alloc_tid, m->alloc_tid); // Does alloc_tid fit into the bitfield? - m->free_tid = kInvalidTid; - m->from_memalign = user_beg != beg_plus_redzone; - if (alloc_beg != chunk_beg) { - CHECK_LE(alloc_beg+ 2 * sizeof(uptr), chunk_beg); - reinterpret_cast(alloc_beg)[0] = kAllocBegMagic; - reinterpret_cast(alloc_beg)[1] = chunk_beg; - } - if (using_primary_allocator) { - CHECK(size); - m->user_requested_size = size; - CHECK(allocator.FromPrimary(allocated)); - } else { - CHECK(!allocator.FromPrimary(allocated)); - m->user_requested_size = SizeClassMap::kMaxSize; - uptr *meta = reinterpret_cast(allocator.GetMetaData(allocated)); - meta[0] = size; - meta[1] = chunk_beg; - } + CHECK(size); + m->SetUsedSize(size); m->user_requested_alignment_log = user_requested_alignment_log; - m->alloc_context_id = StackDepotPut(*stack); + m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack)); uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY); @@ -556,7 +603,11 @@ struct Allocator { : __lsan::kDirectlyLeaked; #endif // Must be the last mutation of metadata in this function. - atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release); + atomic_store(&m->chunk_state, CHUNK_ALLOCATED, memory_order_release); + if (alloc_beg != chunk_beg) { + CHECK_LE(alloc_beg + sizeof(LargeChunkHeader), chunk_beg); + reinterpret_cast(alloc_beg)->Set(m); + } ASAN_MALLOC_HOOK(res, size); return res; } @@ -564,10 +615,10 @@ struct Allocator { // Set quarantine flag if chunk is allocated, issue ASan error report on // available and quarantined chunks. Return true on success, false otherwise. bool AtomicallySetQuarantineFlagIfAllocated(AsanChunk *m, void *ptr, - BufferedStackTrace *stack) { + BufferedStackTrace *stack) { u8 old_chunk_state = CHUNK_ALLOCATED; // Flip the chunk_state atomically to avoid race on double-free. - if (!atomic_compare_exchange_strong((atomic_uint8_t *)m, &old_chunk_state, + if (!atomic_compare_exchange_strong(&m->chunk_state, &old_chunk_state, CHUNK_QUARANTINE, memory_order_acquire)) { ReportInvalidFree(ptr, old_chunk_state, stack); @@ -575,19 +626,18 @@ struct Allocator { return false; } CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state); + // It was a user data. + m->SetFreeContext(kInvalidTid, 0); return true; } // Expects the chunk to already be marked as quarantined by using // AtomicallySetQuarantineFlagIfAllocated. void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack) { - CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); - CHECK_GE(m->alloc_tid, 0); - if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area. - CHECK_EQ(m->free_tid, kInvalidTid); + CHECK_EQ(atomic_load(&m->chunk_state, memory_order_relaxed), + CHUNK_QUARANTINE); AsanThread *t = GetCurrentThread(); - m->free_tid = t ? t->tid() : 0; - m->free_context_id = StackDepotPut(*stack); + m->SetFreeContext(t ? t->tid() : 0, StackDepotPut(*stack)); Flags &fl = *flags(); if (fl.max_free_fill_size > 0) { @@ -676,7 +726,7 @@ struct Allocator { void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true); if (new_ptr) { - u8 chunk_state = m->chunk_state; + u8 chunk_state = atomic_load(&m->chunk_state, memory_order_acquire); if (chunk_state != CHUNK_ALLOCATED) ReportInvalidFree(old_ptr, chunk_state, stack); CHECK_NE(REAL(memcpy), nullptr); @@ -719,17 +769,24 @@ struct Allocator { // -------------------------- Chunk lookup ---------------------- // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg). + // Returns nullptr if AsanChunk is not yet initialized just after + // get_allocator().Allocate(), or is being destroyed just before + // get_allocator().Deallocate(). AsanChunk *GetAsanChunk(void *alloc_beg) { - if (!alloc_beg) return nullptr; - if (!allocator.FromPrimary(alloc_beg)) { - uptr *meta = reinterpret_cast(allocator.GetMetaData(alloc_beg)); - AsanChunk *m = reinterpret_cast(meta[1]); - return m; + if (!alloc_beg) + return nullptr; + AsanChunk *p = reinterpret_cast(alloc_beg)->Get(); + if (!p) { + if (!allocator.FromPrimary(alloc_beg)) + return nullptr; + p = reinterpret_cast(alloc_beg); } - uptr *alloc_magic = reinterpret_cast(alloc_beg); - if (alloc_magic[0] == kAllocBegMagic) - return reinterpret_cast(alloc_magic[1]); - return reinterpret_cast(alloc_beg); + u8 state = atomic_load(&p->chunk_state, memory_order_relaxed); + // It does not guaranty that Chunk is initialized, but it's + // definitely not for any other value. + if (state == CHUNK_ALLOCATED || state == CHUNK_QUARANTINE) + return p; + return nullptr; } AsanChunk *GetAsanChunkByAddr(uptr p) { @@ -747,16 +804,16 @@ struct Allocator { uptr AllocationSize(uptr p) { AsanChunk *m = GetAsanChunkByAddr(p); if (!m) return 0; - if (m->chunk_state != CHUNK_ALLOCATED) return 0; + if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED) + return 0; if (m->Beg() != p) return 0; return m->UsedSize(); } AsanChunkView FindHeapChunkByAddress(uptr addr) { AsanChunk *m1 = GetAsanChunkByAddr(addr); - if (!m1) return AsanChunkView(m1); sptr offset = 0; - if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) { + if (!m1 || AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) { // The address is in the chunk's left redzone, so maybe it is actually // a right buffer overflow from the other chunk to the left. // Search a bit to the left to see if there is another chunk. @@ -813,13 +870,16 @@ static AsanAllocator &get_allocator() { } bool AsanChunkView::IsValid() const { - return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE; + return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) != + CHUNK_INVALID; } bool AsanChunkView::IsAllocated() const { - return chunk_ && chunk_->chunk_state == CHUNK_ALLOCATED; + return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) == + CHUNK_ALLOCATED; } bool AsanChunkView::IsQuarantined() const { - return chunk_ && chunk_->chunk_state == CHUNK_QUARANTINE; + return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) == + CHUNK_QUARANTINE; } uptr AsanChunkView::Beg() const { return chunk_->Beg(); } uptr AsanChunkView::End() const { return Beg() + UsedSize(); } @@ -827,8 +887,23 @@ uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); } u32 AsanChunkView::UserRequestedAlignment() const { return Allocator::ComputeUserAlignment(chunk_->user_requested_alignment_log); } -uptr AsanChunkView::AllocTid() const { return chunk_->alloc_tid; } -uptr AsanChunkView::FreeTid() const { return chunk_->free_tid; } + +uptr AsanChunkView::AllocTid() const { + u32 tid = 0; + u32 stack = 0; + chunk_->GetAllocContext(tid, stack); + return tid; +} + +uptr AsanChunkView::FreeTid() const { + if (!IsQuarantined()) + return kInvalidTid; + u32 tid = 0; + u32 stack = 0; + chunk_->GetFreeContext(tid, stack); + return tid; +} + AllocType AsanChunkView::GetAllocType() const { return (AllocType)chunk_->alloc_type; } @@ -840,8 +915,21 @@ static StackTrace GetStackTraceFromId(u32 id) { return res; } -u32 AsanChunkView::GetAllocStackId() const { return chunk_->alloc_context_id; } -u32 AsanChunkView::GetFreeStackId() const { return chunk_->free_context_id; } +u32 AsanChunkView::GetAllocStackId() const { + u32 tid = 0; + u32 stack = 0; + chunk_->GetAllocContext(tid, stack); + return stack; +} + +u32 AsanChunkView::GetFreeStackId() const { + if (!IsQuarantined()) + return 0; + u32 tid = 0; + u32 stack = 0; + chunk_->GetFreeContext(tid, stack); + return stack; +} StackTrace AsanChunkView::GetAllocStack() const { return GetStackTraceFromId(GetAllocStackId()); @@ -1005,7 +1093,7 @@ void AsanSoftRssLimitExceededCallback(bool limit_exceeded) { instance.SetRssLimitExceeded(limit_exceeded); } -} // namespace __asan +} // namespace __asan // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { @@ -1022,34 +1110,36 @@ void GetAllocatorGlobalRange(uptr *begin, uptr *end) { *end = *begin + sizeof(__asan::get_allocator()); } -uptr PointsIntoChunk(void* p) { +uptr PointsIntoChunk(void *p) { uptr addr = reinterpret_cast(p); __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(addr); - if (!m) return 0; - uptr chunk = m->Beg(); - if (m->chunk_state != __asan::CHUNK_ALLOCATED) + if (!m || atomic_load(&m->chunk_state, memory_order_acquire) != + __asan::CHUNK_ALLOCATED) return 0; - if (m->AddrIsInside(addr, /*locked_version=*/true)) + uptr chunk = m->Beg(); + if (m->AddrIsInside(addr)) return chunk; - if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(/*locked_version*/ true), - addr)) + if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(), addr)) return chunk; return 0; } uptr GetUserBegin(uptr chunk) { __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk); - CHECK(m); - return m->Beg(); + return m ? m->Beg() : 0; } LsanMetadata::LsanMetadata(uptr chunk) { - metadata_ = reinterpret_cast(chunk - __asan::kChunkHeaderSize); + metadata_ = chunk ? reinterpret_cast(chunk - __asan::kChunkHeaderSize) + : nullptr; } bool LsanMetadata::allocated() const { + if (!metadata_) + return false; __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); - return m->chunk_state == __asan::CHUNK_ALLOCATED; + return atomic_load(&m->chunk_state, memory_order_relaxed) == + __asan::CHUNK_ALLOCATED; } ChunkTag LsanMetadata::tag() const { @@ -1064,12 +1154,15 @@ void LsanMetadata::set_tag(ChunkTag value) { uptr LsanMetadata::requested_size() const { __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); - return m->UsedSize(/*locked_version=*/true); + return m->UsedSize(); } u32 LsanMetadata::stack_trace_id() const { __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); - return m->alloc_context_id; + u32 tid = 0; + u32 stack = 0; + m->GetAllocContext(tid, stack); + return stack; } void ForEachChunk(ForEachChunkCallback callback, void *arg) { @@ -1079,16 +1172,45 @@ void ForEachChunk(ForEachChunkCallback callback, void *arg) { IgnoreObjectResult IgnoreObjectLocked(const void *p) { uptr addr = reinterpret_cast(p); __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddr(addr); - if (!m) return kIgnoreObjectInvalid; - if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) { - if (m->lsan_tag == kIgnored) - return kIgnoreObjectAlreadyIgnored; - m->lsan_tag = __lsan::kIgnored; - return kIgnoreObjectSuccess; - } else { + if (!m || + (atomic_load(&m->chunk_state, memory_order_acquire) != + __asan::CHUNK_ALLOCATED) || + !m->AddrIsInside(addr)) { return kIgnoreObjectInvalid; } + if (m->lsan_tag == kIgnored) + return kIgnoreObjectAlreadyIgnored; + m->lsan_tag = __lsan::kIgnored; + return kIgnoreObjectSuccess; +} + +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) { + // Look for the arg pointer of threads that have been created or are running. + // This is necessary to prevent false positive leaks due to the AsanThread + // holding the only live reference to a heap object. This can happen because + // the `pthread_create()` interceptor doesn't wait for the child thread to + // start before returning and thus loosing the the only live reference to the + // heap object on the stack. + + __asan::AsanThreadContext *atctx = + reinterpret_cast<__asan::AsanThreadContext *>(tctx); + __asan::AsanThread *asan_thread = atctx->thread; + + // Note ThreadStatusRunning is required because there is a small window where + // the thread status switches to `ThreadStatusRunning` but the `arg` pointer + // still isn't on the stack yet. + if (atctx->status != ThreadStatusCreated && + atctx->status != ThreadStatusRunning) + return; + + uptr thread_arg = reinterpret_cast(asan_thread->get_arg()); + if (!thread_arg) + return; + + auto ptrsVec = reinterpret_cast *>(ptrs); + ptrsVec->push_back(thread_arg); } + } // namespace __lsan // ---------------------- Interface ---------------- {{{1 diff --git a/system/lib/compiler-rt/lib/asan/asan_allocator.h b/system/lib/compiler-rt/lib/asan/asan_allocator.h index b37d8ef4e8d29..2963e979b55c0 100644 --- a/system/lib/compiler-rt/lib/asan/asan_allocator.h +++ b/system/lib/compiler-rt/lib/asan/asan_allocator.h @@ -15,10 +15,11 @@ #define ASAN_ALLOCATOR_H #include "asan_flags.h" -#include "asan_internal.h" #include "asan_interceptors.h" +#include "asan_internal.h" #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_list.h" +#include "sanitizer_common/sanitizer_platform.h" namespace __asan { @@ -28,7 +29,7 @@ enum AllocType { FROM_NEW_BR = 3 // Memory block came from operator new [ ] }; -struct AsanChunk; +class AsanChunk; struct AllocatorOptions { u32 quarantine_size_mb; @@ -132,6 +133,10 @@ typedef DefaultSizeClassMap SizeClassMap; const uptr kAllocatorSpace = ~(uptr)0; const uptr kAllocatorSize = 0x2000000000ULL; // 128G. typedef VeryCompactSizeClassMap SizeClassMap; +#elif SANITIZER_RISCV64 +const uptr kAllocatorSpace = ~(uptr)0; +const uptr kAllocatorSize = 0x2000000000ULL; // 128G. +typedef VeryDenseSizeClassMap SizeClassMap; # elif defined(__aarch64__) // AArch64/SANITIZER_CAN_USE_ALLOCATOR64 is only for 42-bit VMA // so no need to different values for different VMA. @@ -171,7 +176,7 @@ template struct AP32 { static const uptr kSpaceBeg = 0; static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; - static const uptr kMetadataSize = 16; + static const uptr kMetadataSize = 0; typedef __asan::SizeClassMap SizeClassMap; static const uptr kRegionSizeLog = 20; using AddressSpaceView = AddressSpaceViewTy; diff --git a/system/lib/compiler-rt/lib/asan/asan_emscripten.cpp b/system/lib/compiler-rt/lib/asan/asan_emscripten.cpp index 5c33e7e3b7f50..cb11a93ac754a 100644 --- a/system/lib/compiler-rt/lib/asan/asan_emscripten.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_emscripten.cpp @@ -33,6 +33,8 @@ void *AsanDoesNotSupportStaticLinkage() { void InitializeAsanInterceptors() {} +void FlushUnneededASanShadowMemory(uptr p, uptr size) {} + // We can use a plain thread_local variable for TSD. static thread_local void *per_thread; @@ -65,7 +67,7 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { internal_sched_yield(); emscripten_builtin_free(param); SetCurrentThread(t); - return t->ThreadStart(GetTid(), nullptr); + return t->ThreadStart(GetTid()); } INTERCEPTOR(int, pthread_create, void *thread, diff --git a/system/lib/compiler-rt/lib/asan/asan_flags.cpp b/system/lib/compiler-rt/lib/asan/asan_flags.cpp index a09535f8269e0..197dfb23661af 100644 --- a/system/lib/compiler-rt/lib/asan/asan_flags.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_flags.cpp @@ -32,10 +32,6 @@ namespace __asan { Flags asan_flags_dont_use_directly; // use via flags(). -static const char *MaybeCallAsanDefaultOptions() { - return (&__asan_default_options) ? __asan_default_options() : ""; -} - static const char *MaybeUseAsanDefaultOptionsCompileDefinition() { #ifdef ASAN_DEFAULT_OPTIONS return SANITIZER_STRINGIFY(ASAN_DEFAULT_OPTIONS); @@ -118,14 +114,14 @@ void InitializeFlags() { asan_parser.ParseString(asan_compile_def); // Override from user-specified string. - const char *asan_default_options = MaybeCallAsanDefaultOptions(); + const char *asan_default_options = __asan_default_options(); asan_parser.ParseString(asan_default_options); #if CAN_SANITIZE_UB - const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions(); + const char *ubsan_default_options = __ubsan_default_options(); ubsan_parser.ParseString(ubsan_default_options); #endif #if CAN_SANITIZE_LEAKS - const char *lsan_default_options = __lsan::MaybeCallLsanDefaultOptions(); + const char *lsan_default_options = __lsan_default_options(); lsan_parser.ParseString(lsan_default_options); #endif diff --git a/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp b/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp index f8b2d5f26979d..6c61344f87cfe 100644 --- a/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp @@ -62,6 +62,8 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { UNIMPLEMENTED(); } +bool PlatformUnpoisonStacks() { return false; } + // We can use a plain thread_local variable for TSD. static thread_local void *per_thread; @@ -89,8 +91,7 @@ struct AsanThread::InitOptions { // Shared setup between thread creation and startup for the initial thread. static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, uptr user_id, bool detached, - const char *name, uptr stack_bottom, - uptr stack_size) { + const char *name) { // In lieu of AsanThread::Create. AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__); @@ -99,12 +100,6 @@ static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args); asanThreadRegistry().SetThreadName(tid, name); - // On other systems, AsanThread::Init() is called from the new - // thread itself. But on Fuchsia we already know the stack address - // range beforehand, so we can do most of the setup right now. - const AsanThread::InitOptions options = {stack_bottom, stack_size}; - thread->Init(&options); - return thread; } @@ -133,9 +128,16 @@ AsanThread *CreateMainThread() { _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name, sizeof(name)) == ZX_OK ? name - : nullptr, - __sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize); + : nullptr); + // We need to set the current thread before calling AsanThread::Init() below, + // since it reads the thread ID. SetCurrentThread(t); + DCHECK_EQ(t->tid(), 0); + + const AsanThread::InitOptions options = {__sanitizer::MainThreadStackBase, + __sanitizer::MainThreadStackSize}; + t->Init(&options); + return t; } @@ -151,8 +153,15 @@ static void *BeforeThreadCreateHook(uptr user_id, bool detached, GET_STACK_TRACE_THREAD; u32 parent_tid = GetCurrentTidOrInvalid(); - return CreateAsanThread(&stack, parent_tid, user_id, detached, name, - stack_bottom, stack_size); + AsanThread *thread = + CreateAsanThread(&stack, parent_tid, user_id, detached, name); + + // On other systems, AsanThread::Init() is called from the new + // thread itself. But on Fuchsia we already know the stack address + // range beforehand, so we can do most of the setup right now. + const AsanThread::InitOptions options = {stack_bottom, stack_size}; + thread->Init(&options); + return thread; } // This is called after creating a new thread (in the creating thread), @@ -196,6 +205,10 @@ bool HandleDlopenInit() { return false; } +void FlushUnneededASanShadowMemory(uptr p, uptr size) { + __sanitizer_fill_shadow(p, size, 0, 0); +} + } // namespace __asan // These are declared (in extern "C") by . diff --git a/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp b/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp index 9002c7fe4dbd9..6f124e9770373 100644 --- a/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp @@ -189,20 +189,11 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) #include "sanitizer_common/sanitizer_common_syscalls.inc" #include "sanitizer_common/sanitizer_syscalls_netbsd.inc" -struct ThreadStartParam { - atomic_uintptr_t t; - atomic_uintptr_t is_registered; -}; - #if ASAN_INTERCEPT_PTHREAD_CREATE static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { - ThreadStartParam *param = reinterpret_cast(arg); - AsanThread *t = nullptr; - while ((t = reinterpret_cast( - atomic_load(¶m->t, memory_order_acquire))) == nullptr) - internal_sched_yield(); + AsanThread *t = (AsanThread *)arg; SetCurrentThread(t); - return t->ThreadStart(GetTid(), ¶m->is_registered); + return t->ThreadStart(GetTid()); } INTERCEPTOR(int, pthread_create, void *thread, @@ -215,9 +206,11 @@ INTERCEPTOR(int, pthread_create, void *thread, int detached = 0; if (attr) REAL(pthread_attr_getdetachstate)(attr, &detached); - ThreadStartParam param; - atomic_store(¶m.t, 0, memory_order_relaxed); - atomic_store(¶m.is_registered, 0, memory_order_relaxed); + + u32 current_tid = GetCurrentTidOrInvalid(); + AsanThread *t = + AsanThread::Create(start_routine, arg, current_tid, &stack, detached); + int result; { // Ignore all allocations made by pthread_create: thread stack/TLS may be @@ -227,21 +220,13 @@ INTERCEPTOR(int, pthread_create, void *thread, #if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler disabler; #endif - result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m); + result = REAL(pthread_create)(thread, attr, asan_thread_start, t); } - if (result == 0) { - u32 current_tid = GetCurrentTidOrInvalid(); - AsanThread *t = - AsanThread::Create(start_routine, arg, current_tid, &stack, detached); - atomic_store(¶m.t, reinterpret_cast(t), memory_order_release); - // Wait until the AsanThread object is initialized and the ThreadRegistry - // entry is in "started" state. One reason for this is that after this - // interceptor exits, the child thread's stack may be the only thing holding - // the |arg| pointer. This may cause LSan to report a leak if leak checking - // happens at a point when the interceptor has already exited, but the stack - // range for the child thread is not yet known. - while (atomic_load(¶m.is_registered, memory_order_acquire) == 0) - internal_sched_yield(); + if (result != 0) { + // If the thread didn't start delete the AsanThread to avoid leaking it. + // Note AsanThreadContexts never get destroyed so the AsanThreadContext + // that was just created for the AsanThread is wasted. + t->Destroy(); } return result; } diff --git a/system/lib/compiler-rt/lib/asan/asan_interceptors.h b/system/lib/compiler-rt/lib/asan/asan_interceptors.h index 344a64bd83d33..45cdb80b1b640 100644 --- a/system/lib/compiler-rt/lib/asan/asan_interceptors.h +++ b/system/lib/compiler-rt/lib/asan/asan_interceptors.h @@ -13,9 +13,10 @@ #ifndef ASAN_INTERCEPTORS_H #define ASAN_INTERCEPTORS_H -#include "asan_internal.h" #include "asan_interceptors_memintrinsics.h" +#include "asan_internal.h" #include "interception/interception.h" +#include "sanitizer_common/sanitizer_platform.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" namespace __asan { @@ -59,7 +60,7 @@ void InitializePlatformInterceptors(); # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0 #endif -#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS +#if SANITIZER_GLIBC || SANITIZER_SOLARIS # define ASAN_INTERCEPT_SWAPCONTEXT 1 #else # define ASAN_INTERCEPT_SWAPCONTEXT 0 @@ -71,7 +72,7 @@ void InitializePlatformInterceptors(); # define ASAN_INTERCEPT_SIGLONGJMP 0 #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID +#if SANITIZER_GLIBC # define ASAN_INTERCEPT___LONGJMP_CHK 1 #else # define ASAN_INTERCEPT___LONGJMP_CHK 0 @@ -105,14 +106,15 @@ void InitializePlatformInterceptors(); # define ASAN_INTERCEPT_ATEXIT 0 #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID +#if SANITIZER_GLIBC # define ASAN_INTERCEPT___STRDUP 1 #else # define ASAN_INTERCEPT___STRDUP 0 #endif -#if SANITIZER_LINUX && (defined(__arm__) || defined(__aarch64__) || \ - defined(__i386__) || defined(__x86_64__)) +#if SANITIZER_LINUX && \ + (defined(__arm__) || defined(__aarch64__) || defined(__i386__) || \ + defined(__x86_64__) || SANITIZER_RISCV64) # define ASAN_INTERCEPT_VFORK 1 #else # define ASAN_INTERCEPT_VFORK 0 @@ -132,10 +134,10 @@ DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen) DECLARE_REAL(char*, strstr, const char *s1, const char *s2) #if !SANITIZER_MAC -#define ASAN_INTERCEPT_FUNC(name) \ - do { \ - if (!INTERCEPT_FUNCTION(name)) \ - VReport(1, "AddressSanitizer: failed to intercept '%s'\n'", #name); \ +#define ASAN_INTERCEPT_FUNC(name) \ + do { \ + if (!INTERCEPT_FUNCTION(name)) \ + VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \ } while (0) #define ASAN_INTERCEPT_FUNC_VER(name, ver) \ do { \ diff --git a/system/lib/compiler-rt/lib/asan/asan_interface_internal.h b/system/lib/compiler-rt/lib/asan/asan_interface_internal.h index f14cbbcb76a35..3e6e660288746 100644 --- a/system/lib/compiler-rt/lib/asan/asan_interface_internal.h +++ b/system/lib/compiler-rt/lib/asan/asan_interface_internal.h @@ -173,8 +173,8 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats(); - SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE - const char* __asan_default_options(); + SANITIZER_INTERFACE_ATTRIBUTE + const char *__asan_default_options(); SANITIZER_INTERFACE_ATTRIBUTE extern uptr __asan_shadow_memory_dynamic_address; diff --git a/system/lib/compiler-rt/lib/asan/asan_internal.h b/system/lib/compiler-rt/lib/asan/asan_internal.h index 72a4c3f22ff1c..cfb54927c6cf4 100644 --- a/system/lib/compiler-rt/lib/asan/asan_internal.h +++ b/system/lib/compiler-rt/lib/asan/asan_internal.h @@ -83,6 +83,16 @@ void *AsanDoesNotSupportStaticLinkage(); void AsanCheckDynamicRTPrereqs(); void AsanCheckIncompatibleRT(); +// Unpoisons platform-specific stacks. +// Returns true if all stacks have been unpoisoned. +bool PlatformUnpoisonStacks(); + +// asan_rtl.cpp +// Unpoison a region containing a stack. +// Performs a sanity check and warns if the bounds don't look right. +// The warning contains the type string to identify the stack type. +void UnpoisonStack(uptr bottom, uptr top, const char *type); + // asan_thread.cpp AsanThread *CreateMainThread(); @@ -108,8 +118,6 @@ void AppendToErrorMessageBuffer(const char *buffer); void *AsanDlSymNext(const char *sym); -void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name); - // Returns `true` iff most of ASan init process should be skipped due to the // ASan library being loaded via `dlopen()`. Platforms may perform any // `dlopen()` specific initialization inside this function. diff --git a/system/lib/compiler-rt/lib/asan/asan_linux.cpp b/system/lib/compiler-rt/lib/asan/asan_linux.cpp index ce5e873dc5180..4bcbe5d02e334 100644 --- a/system/lib/compiler-rt/lib/asan/asan_linux.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_linux.cpp @@ -55,6 +55,7 @@ extern Elf_Dyn _DYNAMIC; #else #include #include +extern ElfW(Dyn) _DYNAMIC[]; #endif // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in @@ -84,28 +85,15 @@ bool IsSystemHeapAddress (uptr addr) { return false; } void *AsanDoesNotSupportStaticLinkage() { // This will fail to link with -static. - return &_DYNAMIC; // defined in link.h -} - -static void UnmapFromTo(uptr from, uptr to) { - CHECK(to >= from); - if (to == from) return; - uptr res = internal_munmap(reinterpret_cast(from), to - from); - if (UNLIKELY(internal_iserror(res))) { - Report( - "ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address " - "%p\n", - to - from, to - from, from); - CHECK("unable to unmap" && 0); - } + return &_DYNAMIC; } #if ASAN_PREMAP_SHADOW -uptr FindPremappedShadowStart() { +uptr FindPremappedShadowStart(uptr shadow_size_bytes) { uptr granularity = GetMmapGranularity(); uptr shadow_start = reinterpret_cast(&__asan_shadow); uptr premap_shadow_size = PremapShadowSize(); - uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity); + uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); // We may have mapped too much. Release extra memory. UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); return shadow_start; @@ -113,31 +101,26 @@ uptr FindPremappedShadowStart() { #endif uptr FindDynamicShadowStart() { + uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd); #if ASAN_PREMAP_SHADOW if (!PremapShadowFailed()) - return FindPremappedShadowStart(); + return FindPremappedShadowStart(shadow_size_bytes); #endif - uptr granularity = GetMmapGranularity(); - uptr alignment = granularity * 8; - uptr left_padding = granularity; - uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity); - uptr map_size = shadow_size + left_padding + alignment; - - uptr map_start = (uptr)MmapNoAccess(map_size); - CHECK_NE(map_start, ~(uptr)0); - - uptr shadow_start = RoundUpTo(map_start + left_padding, alignment); - UnmapFromTo(map_start, shadow_start - left_padding); - UnmapFromTo(shadow_start + shadow_size, map_start + map_size); - - return shadow_start; + return MapDynamicShadow(shadow_size_bytes, SHADOW_SCALE, + /*min_shadow_base_alignment*/ 0, kHighMemEnd); } void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { UNIMPLEMENTED(); } +void FlushUnneededASanShadowMemory(uptr p, uptr size) { + // Since asan's mapping is compacting, the shadow chunk may be + // not page-aligned, so we only flush the page-aligned portion. + ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); +} + #if SANITIZER_ANDROID // FIXME: should we do anything for Android? void AsanCheckDynamicRTPrereqs() {} diff --git a/system/lib/compiler-rt/lib/asan/asan_mac.cpp b/system/lib/compiler-rt/lib/asan/asan_mac.cpp index a8d3f5d3473c4..c6950547f089f 100644 --- a/system/lib/compiler-rt/lib/asan/asan_mac.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_mac.cpp @@ -55,46 +55,8 @@ void *AsanDoesNotSupportStaticLinkage() { } uptr FindDynamicShadowStart() { - uptr granularity = GetMmapGranularity(); - uptr alignment = 8 * granularity; - uptr left_padding = granularity; - uptr space_size = kHighShadowEnd + left_padding; - - uptr largest_gap_found = 0; - uptr max_occupied_addr = 0; - VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); - uptr shadow_start = - FindAvailableMemoryRange(space_size, alignment, granularity, - &largest_gap_found, &max_occupied_addr); - // If the shadow doesn't fit, restrict the address space to make it fit. - if (shadow_start == 0) { - VReport( - 2, - "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n", - largest_gap_found, max_occupied_addr); - uptr new_max_vm = RoundDownTo(largest_gap_found << SHADOW_SCALE, alignment); - if (new_max_vm < max_occupied_addr) { - Report("Unable to find a memory range for dynamic shadow.\n"); - Report( - "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, " - "new_max_vm = %p\n", - space_size, largest_gap_found, max_occupied_addr, new_max_vm); - CHECK(0 && "cannot place shadow"); - } - RestrictMemoryToMaxAddress(new_max_vm); - kHighMemEnd = new_max_vm - 1; - space_size = kHighShadowEnd + left_padding; - VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); - shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity, - nullptr, nullptr); - if (shadow_start == 0) { - Report("Unable to find a memory range after restricting VM.\n"); - CHECK(0 && "cannot place shadow after restricting vm"); - } - } - CHECK_NE((uptr)0, shadow_start); - CHECK(IsAligned(shadow_start, alignment)); - return shadow_start; + return MapDynamicShadow(MemToShadowSize(kHighMemEnd), SHADOW_SCALE, + /*min_shadow_base_alignment*/ 0, kHighMemEnd); } // No-op. Mac does not support static linkage anyway. @@ -127,6 +89,12 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { op(globals, size / sizeof(__asan_global)); } +void FlushUnneededASanShadowMemory(uptr p, uptr size) { + // Since asan's mapping is compacting, the shadow chunk may be + // not page-aligned, so we only flush the page-aligned portion. + ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); +} + void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } diff --git a/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp b/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp index 20719cd51f959..7d7b3631a187c 100644 --- a/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp @@ -35,7 +35,7 @@ static uptr last_dlsym_alloc_size_in_words; static const uptr kDlsymAllocPoolSize = SANITIZER_RTEMS ? 4096 : 1024; static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; -static INLINE bool IsInDlsymAllocPool(const void *ptr) { +static inline bool IsInDlsymAllocPool(const void *ptr) { uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; return off < allocated_for_dlsym * sizeof(alloc_memory_for_dlsym[0]); } @@ -96,12 +96,12 @@ bool IsFromLocalPool(const void *ptr) { } #endif -static INLINE bool MaybeInDlsym() { +static inline bool MaybeInDlsym() { // Fuchsia doesn't use dlsym-based interceptors. return !SANITIZER_FUCHSIA && asan_init_is_running; } -static INLINE bool UseLocalPool() { +static inline bool UseLocalPool() { return EarlyMalloc() || MaybeInDlsym(); } @@ -121,19 +121,19 @@ static void *ReallocFromLocalPool(void *ptr, uptr size) { } INTERCEPTOR(void, free, void *ptr) { - GET_STACK_TRACE_FREE; if (UNLIKELY(IsInDlsymAllocPool(ptr))) { DeallocateFromLocalPool(ptr); return; } + GET_STACK_TRACE_FREE; asan_free(ptr, &stack, FROM_MALLOC); } #if SANITIZER_INTERCEPT_CFREE INTERCEPTOR(void, cfree, void *ptr) { - GET_STACK_TRACE_FREE; if (UNLIKELY(IsInDlsymAllocPool(ptr))) return; + GET_STACK_TRACE_FREE; asan_free(ptr, &stack, FROM_MALLOC); } #endif // SANITIZER_INTERCEPT_CFREE diff --git a/system/lib/compiler-rt/lib/asan/asan_malloc_local.h b/system/lib/compiler-rt/lib/asan/asan_malloc_local.h index 3f784b90c739c..e2c9be0379f2f 100644 --- a/system/lib/compiler-rt/lib/asan/asan_malloc_local.h +++ b/system/lib/compiler-rt/lib/asan/asan_malloc_local.h @@ -17,7 +17,7 @@ #include "sanitizer_common/sanitizer_platform.h" #include "asan_internal.h" -static INLINE bool EarlyMalloc() { +static inline bool EarlyMalloc() { return SANITIZER_RTEMS && (!__asan::asan_inited || __asan::asan_init_is_running); } diff --git a/system/lib/compiler-rt/lib/asan/asan_mapping.h b/system/lib/compiler-rt/lib/asan/asan_mapping.h index 67c5448729a3d..aa499376df64f 100644 --- a/system/lib/compiler-rt/lib/asan/asan_mapping.h +++ b/system/lib/compiler-rt/lib/asan/asan_mapping.h @@ -79,6 +79,20 @@ // || `[0x1000000000, 0x11ffffffff]` || lowshadow || // || `[0x0000000000, 0x0fffffffff]` || lowmem || // +// RISC-V has only 38 bits for task size +// Low mem size is set with kRiscv64_ShadowOffset64 in +// compiler-rt/lib/asan/asan_allocator.h and in +// llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp with +// kRiscv64_ShadowOffset64, High mem top border is set with +// GetMaxVirtualAddress() in +// compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +// Default Linux/RISCV64 Sv39/Sv48 mapping: +// || `[0x000820000000, 0x003fffffffff]` || HighMem || +// || `[0x000124000000, 0x00081fffffff]` || HighShadow || +// || `[0x000024000000, 0x000123ffffff]` || ShadowGap || +// || `[0x000020000000, 0x000023ffffff]` || LowShadow || +// || `[0x000000000000, 0x00001fffffff]` || LowMem || +// // Default Linux/AArch64 (42-bit VMA) mapping: // || `[0x10000000000, 0x3ffffffffff]` || highmem || // || `[0x0a000000000, 0x0ffffffffff]` || highshadow || @@ -161,6 +175,7 @@ static const u64 kDefaultShadowOffset64 = 1ULL << 44; static const u64 kDefaultShort64bitShadowOffset = 0x7FFFFFFF & (~0xFFFULL << kDefaultShadowScale); // < 2G. static const u64 kAArch64_ShadowOffset64 = 1ULL << 36; +static const u64 kRiscv64_ShadowOffset64 = 0x20000000; static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000; static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37; static const u64 kPPC64_ShadowOffset64 = 1ULL << 44; @@ -206,6 +221,10 @@ static const u64 kMyriadCacheBitMask32 = 0x40000000ULL; #else # if SANITIZER_IOS # define SHADOW_OFFSET __asan_shadow_memory_dynamic_address +# elif SANITIZER_MAC && defined(__aarch64__) +# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address +#elif SANITIZER_RISCV64 +#define SHADOW_OFFSET kRiscv64_ShadowOffset64 # elif defined(__aarch64__) # define SHADOW_OFFSET kAArch64_ShadowOffset64 # elif defined(__powerpc64__) @@ -355,6 +374,8 @@ static inline bool AddrIsInShadowGap(uptr a) { namespace __asan { +static inline uptr MemToShadowSize(uptr size) { return size >> SHADOW_SCALE; } + static inline bool AddrIsInMem(uptr a) { PROFILE_ASAN_MAPPING(); return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a) || diff --git a/system/lib/compiler-rt/lib/asan/asan_poisoning.cpp b/system/lib/compiler-rt/lib/asan/asan_poisoning.cpp index a3152eab85409..15be546f62b23 100644 --- a/system/lib/compiler-rt/lib/asan/asan_poisoning.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_poisoning.cpp @@ -62,14 +62,6 @@ struct ShadowSegmentEndpoint { } }; -void FlushUnneededASanShadowMemory(uptr p, uptr size) { - // Since asan's mapping is compacting, the shadow chunk may be - // not page-aligned, so we only flush the page-aligned portion. -#if !SANITIZER_EMSCRIPTEN - ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); -#endif -} - void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) { uptr end = ptr + size; if (Verbosity()) { diff --git a/system/lib/compiler-rt/lib/asan/asan_posix.cpp b/system/lib/compiler-rt/lib/asan/asan_posix.cpp index 85ebd181ebf2f..6e49520498158 100644 --- a/system/lib/compiler-rt/lib/asan/asan_posix.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_posix.cpp @@ -17,6 +17,7 @@ #include "asan_internal.h" #include "asan_interceptors.h" #include "asan_mapping.h" +#include "asan_poisoning.h" #include "asan_report.h" #include "asan_stack.h" #include "sanitizer_common/sanitizer_libc.h" @@ -24,6 +25,7 @@ #include "sanitizer_common/sanitizer_procmaps.h" #include +#include #include #include #include @@ -37,6 +39,36 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ReportDeadlySignal(sig); } +bool PlatformUnpoisonStacks() { +#if SANITIZER_EMSCRIPTEN + return false; +#else + stack_t signal_stack; + CHECK_EQ(0, sigaltstack(nullptr, &signal_stack)); + uptr sigalt_bottom = (uptr)signal_stack.ss_sp; + uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size); + // If we're executing on the signal alternate stack AND the Linux flag + // SS_AUTODISARM was used, then we cannot get the signal alternate stack + // bounds from sigaltstack -- sigaltstack's output looks just as if no + // alternate stack has ever been set up. + // We're always unpoisoning the signal alternate stack to support jumping + // between the default stack and signal alternate stack. + if (signal_stack.ss_flags != SS_DISABLE) + UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt"); + + if (signal_stack.ss_flags != SS_ONSTACK) + return false; + + // Since we're on the signal altnerate stack, we cannot find the DEFAULT + // stack bottom using a local variable. + uptr default_bottom, tls_addr, tls_size, stack_size; + GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr, + &tls_size); + UnpoisonStack(default_bottom, default_bottom + stack_size, "default"); + return true; +#endif +} + // ---------------------- TSD ---------------- {{{1 #if SANITIZER_NETBSD && !ASAN_DYNAMIC diff --git a/system/lib/compiler-rt/lib/asan/asan_premap_shadow.cpp b/system/lib/compiler-rt/lib/asan/asan_premap_shadow.cpp index 7835e99748ffa..666bb9b34bd39 100644 --- a/system/lib/compiler-rt/lib/asan/asan_premap_shadow.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_premap_shadow.cpp @@ -32,22 +32,8 @@ uptr PremapShadowSize() { // Returns an address aligned to 8 pages, such that one page on the left and // PremapShadowSize() bytes on the right of it are mapped r/o. uptr PremapShadow() { - uptr granularity = GetMmapGranularity(); - uptr alignment = granularity * 8; - uptr left_padding = granularity; - uptr shadow_size = PremapShadowSize(); - uptr map_size = shadow_size + left_padding + alignment; - - uptr map_start = (uptr)MmapNoAccess(map_size); - CHECK_NE(map_start, ~(uptr)0); - - uptr shadow_start = RoundUpTo(map_start + left_padding, alignment); - uptr shadow_end = shadow_start + shadow_size; - internal_munmap(reinterpret_cast(map_start), - shadow_start - left_padding - map_start); - internal_munmap(reinterpret_cast(shadow_end), - map_start + map_size - shadow_end); - return shadow_start; + return MapDynamicShadow(PremapShadowSize(), /*mmap_alignment_scale*/ 3, + /*min_shadow_base_alignment*/ 0, kHighMemEnd); } bool PremapShadowFailed() { diff --git a/system/lib/compiler-rt/lib/asan/asan_report.cpp b/system/lib/compiler-rt/lib/asan/asan_report.cpp index 2e6ce436d0306..03f1ed2b01866 100644 --- a/system/lib/compiler-rt/lib/asan/asan_report.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_report.cpp @@ -151,7 +151,8 @@ class ScopedInErrorReport { if (common_flags()->print_cmdline) PrintCmdline(); - if (common_flags()->print_module_map == 2) PrintModuleMap(); + if (common_flags()->print_module_map == 2) + DumpProcessMap(); // Copy the message buffer so that we could start logging without holding a // lock that gets aquired during printing. @@ -160,6 +161,9 @@ class ScopedInErrorReport { BlockingMutexLock l(&error_message_buf_mutex); internal_memcpy(buffer_copy.data(), error_message_buffer, kErrorMessageBufferSize); + // Clear error_message_buffer so that if we find other errors + // we don't re-log this error. + error_message_buffer_pos = 0; } LogFullErrorReport(buffer_copy.data()); @@ -408,7 +412,7 @@ static bool IsInvalidPointerPair(uptr a1, uptr a2) { return false; } -static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { +static inline void CheckForInvalidPointerPair(void *p1, void *p2) { switch (flags()->detect_invalid_pointer_pairs) { case 0: return; diff --git a/system/lib/compiler-rt/lib/asan/asan_rtems.cpp b/system/lib/compiler-rt/lib/asan/asan_rtems.cpp index ecd568c5981bb..ea0b4ad9db681 100644 --- a/system/lib/compiler-rt/lib/asan/asan_rtems.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_rtems.cpp @@ -50,6 +50,12 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { UNIMPLEMENTED(); } +void FlushUnneededASanShadowMemory(uptr p, uptr size) { + // Since asan's mapping is compacting, the shadow chunk may be + // not page-aligned, so we only flush the page-aligned portion. + ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); +} + void AsanCheckDynamicRTPrereqs() {} void AsanCheckIncompatibleRT() {} void InitializeAsanInterceptors() {} @@ -64,6 +70,8 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { UNIMPLEMENTED(); } +bool PlatformUnpoisonStacks() { return false; } + void EarlyInit() { // Provide early initialization of shadow memory so that // instrumented code running before full initialzation will not diff --git a/system/lib/compiler-rt/lib/asan/asan_rtl.cpp b/system/lib/compiler-rt/lib/asan/asan_rtl.cpp index 5665654e942fb..3acaa74e3f5ea 100644 --- a/system/lib/compiler-rt/lib/asan/asan_rtl.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_rtl.cpp @@ -45,7 +45,8 @@ static void AsanDie() { // Don't die twice - run a busy loop. while (1) { } } - if (common_flags()->print_module_map >= 1) PrintModuleMap(); + if (common_flags()->print_module_map >= 1) + DumpProcessMap(); if (flags()->sleep_before_dying) { Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying); SleepForSeconds(flags()->sleep_before_dying); @@ -321,7 +322,7 @@ static void InitializeHighMemEnd() { kHighMemEnd = GetMaxUserVirtualAddress(); // Increase kHighMemEnd to make sure it's properly // aligned together with kHighMemBeg: - kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1; + kHighMemEnd |= (GetMmapGranularity() << SHADOW_SCALE) - 1; #endif // !ASAN_FIXED_MAPPING CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0); #endif // !SANITIZER_MYRIAD2 @@ -555,22 +556,33 @@ class AsanInitializer { static AsanInitializer asan_initializer; #endif // ASAN_DYNAMIC -} // namespace __asan - -// ---------------------- Interface ---------------- {{{1 -using namespace __asan; - -void NOINLINE __asan_handle_no_return() { - if (asan_init_is_running) +void UnpoisonStack(uptr bottom, uptr top, const char *type) { + static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M + if (top - bottom > kMaxExpectedCleanupSize) { + static bool reported_warning = false; + if (reported_warning) + return; + reported_warning = true; + Report( + "WARNING: ASan is ignoring requested __asan_handle_no_return: " + "stack type: %s top: %p; bottom %p; size: %p (%zd)\n" + "False positive error reports may follow\n" + "For details see " + "https://github.com/google/sanitizers/issues/189\n", + type, top, bottom, top - bottom, top - bottom); return; + } + PoisonShadow(bottom, top - bottom, 0); +} - int local_stack; - AsanThread *curr_thread = GetCurrentThread(); - uptr PageSize = GetPageSizeCached(); - uptr top, bottom; - if (curr_thread) { +static void UnpoisonDefaultStack() { + uptr bottom, top; + + if (AsanThread *curr_thread = GetCurrentThread()) { + int local_stack; + const uptr page_size = GetPageSizeCached(); top = curr_thread->stack_top(); - bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1); + bottom = ((uptr)&local_stack - page_size) & ~(page_size - 1); } else if (SANITIZER_RTEMS) { // Give up On RTEMS. return; @@ -582,25 +594,31 @@ void NOINLINE __asan_handle_no_return() { &tls_size); top = bottom + stack_size; } - static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M - if (top - bottom > kMaxExpectedCleanupSize) { - static bool reported_warning = false; - if (reported_warning) - return; - reported_warning = true; - Report("WARNING: ASan is ignoring requested __asan_handle_no_return: " - "stack top: %p; bottom %p; size: %p (%zd)\n" - "False positive error reports may follow\n" - "For details see " - "https://github.com/google/sanitizers/issues/189\n", - top, bottom, top - bottom, top - bottom); - return; - } - PoisonShadow(bottom, top - bottom, 0); + + UnpoisonStack(bottom, top, "default"); +} + +static void UnpoisonFakeStack() { + AsanThread *curr_thread = GetCurrentThread(); if (curr_thread && curr_thread->has_fake_stack()) curr_thread->fake_stack()->HandleNoReturn(); } +} // namespace __asan + +// ---------------------- Interface ---------------- {{{1 +using namespace __asan; + +void NOINLINE __asan_handle_no_return() { + if (asan_init_is_running) + return; + + if (!PlatformUnpoisonStacks()) + UnpoisonDefaultStack(); + + UnpoisonFakeStack(); +} + extern "C" void *__asan_extra_spill_area() { AsanThread *t = GetCurrentThread(); CHECK(t); diff --git a/system/lib/compiler-rt/lib/asan/asan_shadow_setup.cpp b/system/lib/compiler-rt/lib/asan/asan_shadow_setup.cpp index e17da6a3696a9..9b9e7ae3fe15f 100644 --- a/system/lib/compiler-rt/lib/asan/asan_shadow_setup.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_shadow_setup.cpp @@ -22,24 +22,6 @@ namespace __asan { -// ---------------------- mmap -------------------- {{{1 -// Reserve memory range [beg, end]. -// We need to use inclusive range because end+1 may not be representable. -void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { - CHECK_EQ((beg % GetMmapGranularity()), 0); - CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); - uptr size = end - beg + 1; - DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. - if (!MmapFixedSuperNoReserve(beg, size, name)) { - Report( - "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " - "Perhaps you're using ulimit -v\n", - size); - Abort(); - } - if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size); -} - static void ProtectGap(uptr addr, uptr size) { if (!flags()->protect_shadow_gap) { // The shadow gap is unprotected, so there is a chance that someone @@ -57,30 +39,13 @@ static void ProtectGap(uptr addr, uptr size) { "unprotected gap shadow"); return; } - void *res = MmapFixedNoAccess(addr, size, "shadow gap"); - if (addr == (uptr)res) return; - // A few pages at the start of the address space can not be protected. - // But we really want to protect as much as possible, to prevent this memory - // being returned as a result of a non-FIXED mmap(). - if (addr == kZeroBaseShadowStart) { - uptr step = GetMmapGranularity(); - while (size > step && addr < kZeroBaseMaxShadowStart) { - addr += step; - size -= step; - void *res = MmapFixedNoAccess(addr, size, "shadow gap"); - if (addr == (uptr)res) return; - } - } - - Report( - "ERROR: Failed to protect the shadow gap. " - "ASan cannot proceed correctly. ABORTING.\n"); - DumpProcessMap(); - Die(); + __sanitizer::ProtectGap(addr, size, kZeroBaseShadowStart, + kZeroBaseMaxShadowStart); } static void MaybeReportLinuxPIEBug() { -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__)) +#if SANITIZER_LINUX && \ + (defined(__x86_64__) || defined(__aarch64__) || SANITIZER_RISCV64) Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n"); Report( "See https://github.com/google/sanitizers/issues/856 for possible " @@ -99,8 +64,6 @@ void InitializeShadowMemory() { // |kDefaultShadowSentinel|. bool full_shadow_is_available = false; if (shadow_start == kDefaultShadowSentinel) { - __asan_shadow_memory_dynamic_address = 0; - CHECK_EQ(0, kLowShadowBeg); shadow_start = FindDynamicShadowStart(); if (SANITIZER_LINUX) full_shadow_is_available = true; } diff --git a/system/lib/compiler-rt/lib/asan/asan_stack.h b/system/lib/compiler-rt/lib/asan/asan_stack.h index 4089d3d7340ee..47ca85a164435 100644 --- a/system/lib/compiler-rt/lib/asan/asan_stack.h +++ b/system/lib/compiler-rt/lib/asan/asan_stack.h @@ -51,11 +51,6 @@ u32 GetMallocContextSize(); stack.Unwind(pc, bp, nullptr, \ common_flags()->fast_unwind_on_fatal) -#define GET_STACK_TRACE_SIGNAL(sig) \ - BufferedStackTrace stack; \ - stack.Unwind((sig).pc, (sig).bp, (sig).context, \ - common_flags()->fast_unwind_on_fatal) - #define GET_STACK_TRACE_FATAL_HERE \ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal) diff --git a/system/lib/compiler-rt/lib/asan/asan_thread.cpp b/system/lib/compiler-rt/lib/asan/asan_thread.cpp index b573b7f2817b1..a15571b0e4258 100644 --- a/system/lib/compiler-rt/lib/asan/asan_thread.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_thread.cpp @@ -190,7 +190,7 @@ uptr AsanThread::stack_size() { return bounds.top - bounds.bottom; } -// We want to create the FakeStack lazyly on the first use, but not eralier +// We want to create the FakeStack lazily on the first use, but not earlier // than the stack size is known and the procedure has to be async-signal safe. FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { uptr stack_size = this->stack_size(); @@ -213,6 +213,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { stack_size_log = Max(stack_size_log, static_cast(flags()->min_uar_stack_size_log)); fake_stack_ = FakeStack::Create(stack_size_log); + DCHECK_EQ(GetCurrentThread(), this); SetTLSFakeStack(fake_stack_); return fake_stack_; } @@ -220,6 +221,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { } void AsanThread::Init(const InitOptions *options) { + DCHECK_NE(tid(), ThreadRegistry::kUnknownTid); next_stack_top_ = next_stack_bottom_ = 0; atomic_store(&stack_switching_, false, memory_order_release); CHECK_EQ(this->stack_size(), 0U); @@ -231,8 +233,17 @@ void AsanThread::Init(const InitOptions *options) { } ClearShadowForThreadStackAndTLS(); fake_stack_ = nullptr; - if (__asan_option_detect_stack_use_after_return) + if (__asan_option_detect_stack_use_after_return && + tid() == GetCurrentTidOrInvalid()) { + // AsyncSignalSafeLazyInitFakeStack makes use of threadlocals and must be + // called from the context of the thread it is initializing, not its parent. + // Most platforms call AsanThread::Init on the newly-spawned thread, but + // Fuchsia calls this function from the parent thread. To support that + // approach, we avoid calling AsyncSignalSafeLazyInitFakeStack here; it will + // be called by the new thread when it first attempts to access the fake + // stack. AsyncSignalSafeLazyInitFakeStack(); + } int local = 0; VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_, @@ -244,12 +255,9 @@ void AsanThread::Init(const InitOptions *options) { // SetThreadStackAndTls. #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS -thread_return_t AsanThread::ThreadStart( - tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) { +thread_return_t AsanThread::ThreadStart(tid_t os_id) { Init(); asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr); - if (signal_thread_is_registered) - atomic_store(signal_thread_is_registered, 1, memory_order_release); #if !SANITIZER_EMSCRIPTEN if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); @@ -281,8 +289,7 @@ AsanThread *CreateMainThread() { /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0, /* stack */ nullptr, /* detached */ true); SetCurrentThread(main_thread); - main_thread->ThreadStart(internal_getpid(), - /* signal_thread_is_registered */ nullptr); + main_thread->ThreadStart(internal_getpid()); return main_thread; } @@ -370,7 +377,9 @@ uptr AsanThread::GetStackVariableShadowStart(uptr addr) { bottom = stack_bottom(); } else if (has_fake_stack()) { bottom = fake_stack()->AddrIsInFakeStack(addr); - CHECK(bottom); + if (bottom == 0) { + return 0; + } } else { return 0; } @@ -484,6 +493,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, return true; } +void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches) {} + void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, void *arg) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); diff --git a/system/lib/compiler-rt/lib/asan/asan_thread.h b/system/lib/compiler-rt/lib/asan/asan_thread.h index c503f507059dd..c33955eee367b 100644 --- a/system/lib/compiler-rt/lib/asan/asan_thread.h +++ b/system/lib/compiler-rt/lib/asan/asan_thread.h @@ -35,7 +35,7 @@ class AsanThread; // These objects are created for every thread and are never deleted, // so we can find them by tid even if the thread is long dead. -class AsanThreadContext : public ThreadContextBase { +class AsanThreadContext final : public ThreadContextBase { public: explicit AsanThreadContext(int tid) : ThreadContextBase(tid), announced(false), @@ -69,8 +69,7 @@ class AsanThread { struct InitOptions; void Init(const InitOptions *options = nullptr); - thread_return_t ThreadStart(tid_t os_id, - atomic_uintptr_t *signal_thread_is_registered); + thread_return_t ThreadStart(tid_t os_id); uptr stack_top(); uptr stack_bottom(); @@ -132,6 +131,8 @@ class AsanThread { void *extra_spill_area() { return &extra_spill_area_; } + void *get_arg() { return arg_; } + private: // NOTE: There is no AsanThread constructor. It is allocated // via mmap() and *must* be valid in zero-initialized state. diff --git a/system/lib/compiler-rt/lib/asan/asan_win.cpp b/system/lib/compiler-rt/lib/asan/asan_win.cpp index 417892aaedd8e..1577c83cf9941 100644 --- a/system/lib/compiler-rt/lib/asan/asan_win.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_win.cpp @@ -134,7 +134,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { AsanThread *t = (AsanThread *)arg; SetCurrentThread(t); - return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr); + return t->ThreadStart(GetTid()); } INTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security, @@ -191,6 +191,12 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { UNIMPLEMENTED(); } +void FlushUnneededASanShadowMemory(uptr p, uptr size) { + // Since asan's mapping is compacting, the shadow chunk may be + // not page-aligned, so we only flush the page-aligned portion. + ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); +} + // ---------------------- TSD ---------------- {{{ static bool tsd_key_inited = false; @@ -247,15 +253,8 @@ void *AsanDoesNotSupportStaticLinkage() { } uptr FindDynamicShadowStart() { - uptr granularity = GetMmapGranularity(); - uptr alignment = 8 * granularity; - uptr left_padding = granularity; - uptr space_size = kHighShadowEnd + left_padding; - uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, - granularity, nullptr, nullptr); - CHECK_NE((uptr)0, shadow_start); - CHECK(IsAligned(shadow_start, alignment)); - return shadow_start; + return MapDynamicShadow(MemToShadowSize(kHighMemEnd), SHADOW_SCALE, + /*min_shadow_base_alignment*/ 0, kHighMemEnd); } void AsanCheckDynamicRTPrereqs() {} @@ -268,6 +267,8 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) { void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); } +bool PlatformUnpoisonStacks() { return false; } + #if SANITIZER_WINDOWS64 // Exception handler for dealing with shadow memory. static LONG CALLBACK diff --git a/system/lib/compiler-rt/lib/builtins/absvsi2.c b/system/lib/compiler-rt/lib/builtins/absvsi2.c index 44ada169e7e66..9d5de7e8a3f22 100644 --- a/system/lib/compiler-rt/lib/builtins/absvsi2.c +++ b/system/lib/compiler-rt/lib/builtins/absvsi2.c @@ -18,7 +18,7 @@ COMPILER_RT_ABI si_int __absvsi2(si_int a) { const int N = (int)(sizeof(si_int) * CHAR_BIT); - if (a == (1 << (N - 1))) + if (a == ((si_int)1 << (N - 1))) compilerrt_abort(); const si_int t = a >> (N - 1); return (a ^ t) - t; diff --git a/system/lib/compiler-rt/lib/builtins/ashldi3.c b/system/lib/compiler-rt/lib/builtins/ashldi3.c index 7c81057a22847..04f22228f11db 100644 --- a/system/lib/compiler-rt/lib/builtins/ashldi3.c +++ b/system/lib/compiler-rt/lib/builtins/ashldi3.c @@ -16,7 +16,7 @@ // Precondition: 0 <= b < bits_in_dword -COMPILER_RT_ABI di_int __ashldi3(di_int a, si_int b) { +COMPILER_RT_ABI di_int __ashldi3(di_int a, int b) { const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT); dwords input; dwords result; diff --git a/system/lib/compiler-rt/lib/builtins/ashrdi3.c b/system/lib/compiler-rt/lib/builtins/ashrdi3.c index b9939132205c8..934a5c47fd69b 100644 --- a/system/lib/compiler-rt/lib/builtins/ashrdi3.c +++ b/system/lib/compiler-rt/lib/builtins/ashrdi3.c @@ -16,7 +16,7 @@ // Precondition: 0 <= b < bits_in_dword -COMPILER_RT_ABI di_int __ashrdi3(di_int a, si_int b) { +COMPILER_RT_ABI di_int __ashrdi3(di_int a, int b) { const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT); dwords input; dwords result; diff --git a/system/lib/compiler-rt/lib/builtins/assembly.h b/system/lib/compiler-rt/lib/builtins/assembly.h index f437cb87f60ac..f6ce6a9fccff3 100644 --- a/system/lib/compiler-rt/lib/builtins/assembly.h +++ b/system/lib/compiler-rt/lib/builtins/assembly.h @@ -14,8 +14,8 @@ #ifndef COMPILERRT_ASSEMBLY_H #define COMPILERRT_ASSEMBLY_H -#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) -#define SEPARATOR @ +#if defined(__APPLE__) && defined(__aarch64__) +#define SEPARATOR %% #else #define SEPARATOR ; #endif @@ -35,14 +35,14 @@ #define HIDDEN(name) .hidden name #define LOCAL_LABEL(name) .L_##name #define FILE_LEVEL_DIRECTIVE -#if defined(__arm__) +#if defined(__arm__) || defined(__aarch64__) #define SYMBOL_IS_FUNC(name) .type name,%function #else #define SYMBOL_IS_FUNC(name) .type name,@function #endif #define CONST_SECTION .section .rodata -#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ +#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ defined(__linux__) #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits #else @@ -65,6 +65,66 @@ #endif +#if defined(__arm__) || defined(__aarch64__) +#define FUNC_ALIGN \ + .text SEPARATOR \ + .balign 16 SEPARATOR +#else +#define FUNC_ALIGN +#endif + +// BTI and PAC gnu property note +#define NT_GNU_PROPERTY_TYPE_0 5 +#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000 +#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1 +#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2 + +#if defined(__ARM_FEATURE_BTI_DEFAULT) +#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI +#else +#define BTI_FLAG 0 +#endif + +#if __ARM_FEATURE_PAC_DEFAULT & 3 +#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC +#else +#define PAC_FLAG 0 +#endif + +#define GNU_PROPERTY(type, value) \ + .pushsection .note.gnu.property, "a" SEPARATOR \ + .p2align 3 SEPARATOR \ + .word 4 SEPARATOR \ + .word 16 SEPARATOR \ + .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR \ + .asciz "GNU" SEPARATOR \ + .word type SEPARATOR \ + .word 4 SEPARATOR \ + .word value SEPARATOR \ + .word 0 SEPARATOR \ + .popsection + +#if BTI_FLAG != 0 +#define BTI_C bti c +#else +#define BTI_C +#endif + +#if (BTI_FLAG | PAC_FLAG) != 0 +#define GNU_PROPERTY_BTI_PAC \ + GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG) +#else +#define GNU_PROPERTY_BTI_PAC +#endif + +#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM) +#define CFI_START .cfi_startproc +#define CFI_END .cfi_endproc +#else +#define CFI_START +#define CFI_END +#endif + #if defined(__arm__) // Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros: @@ -131,8 +191,14 @@ #define DEFINE_CODE_STATE #endif -#define GLUE2(a, b) a##b -#define GLUE(a, b) GLUE2(a, b) +#define GLUE2_(a, b) a##b +#define GLUE(a, b) GLUE2_(a, b) +#define GLUE2(a, b) GLUE2_(a, b) +#define GLUE3_(a, b, c) a##b##c +#define GLUE3(a, b, c) GLUE3_(a, b, c) +#define GLUE4_(a, b, c, d) a##b##c##d +#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d) + #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) #ifdef VISIBILITY_HIDDEN @@ -177,6 +243,16 @@ DECLARE_FUNC_ENCODING \ name: +#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \ + DEFINE_CODE_STATE \ + FUNC_ALIGN \ + .globl name SEPARATOR \ + SYMBOL_IS_FUNC(name) SEPARATOR \ + DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \ + CFI_START SEPARATOR \ + DECLARE_FUNC_ENCODING \ + name: SEPARATOR BTI_C + #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ @@ -193,8 +269,13 @@ #ifdef __ELF__ #define END_COMPILERRT_FUNCTION(name) \ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name) +#define END_COMPILERRT_OUTLINE_FUNCTION(name) \ + CFI_END SEPARATOR \ + .size SYMBOL_NAME(name), . - SYMBOL_NAME(name) #else #define END_COMPILERRT_FUNCTION(name) +#define END_COMPILERRT_OUTLINE_FUNCTION(name) \ + CFI_END #endif #endif // COMPILERRT_ASSEMBLY_H diff --git a/system/lib/compiler-rt/lib/builtins/atomic.c b/system/lib/compiler-rt/lib/builtins/atomic.c index 32b3a0f9ad239..f48cdc10ccf7a 100644 --- a/system/lib/compiler-rt/lib/builtins/atomic.c +++ b/system/lib/compiler-rt/lib/builtins/atomic.c @@ -23,6 +23,7 @@ // //===----------------------------------------------------------------------===// +#include #include #include @@ -35,6 +36,8 @@ #pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange) #pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME( \ __atomic_compare_exchange) +#pragma redefine_extname __atomic_is_lock_free_c SYMBOL_NAME( \ + __atomic_is_lock_free) /// Number of locks. This allocates one page on 32-bit platforms, two on /// 64-bit. This can be specified externally if a different trade between @@ -119,56 +122,58 @@ static __inline Lock *lock_for_pointer(void *ptr) { return locks + (hash & SPINLOCK_MASK); } -/// Macros for determining whether a size is lock free. Clang can not yet -/// codegen __atomic_is_lock_free(16), so for now we assume 16-byte values are -/// not lock free. -#define IS_LOCK_FREE_1 __c11_atomic_is_lock_free(1) -#define IS_LOCK_FREE_2 __c11_atomic_is_lock_free(2) -#define IS_LOCK_FREE_4 __c11_atomic_is_lock_free(4) -#define IS_LOCK_FREE_8 __c11_atomic_is_lock_free(8) -#define IS_LOCK_FREE_16 0 +/// Macros for determining whether a size is lock free. +#define ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(size, p) \ + (__atomic_always_lock_free(size, p) || \ + (__atomic_always_lock_free(size, 0) && ((uintptr_t)p % size) == 0)) +#define IS_LOCK_FREE_1(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(1, p) +#define IS_LOCK_FREE_2(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(2, p) +#define IS_LOCK_FREE_4(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(4, p) +#define IS_LOCK_FREE_8(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(8, p) +#define IS_LOCK_FREE_16(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(16, p) /// Macro that calls the compiler-generated lock-free versions of functions /// when they exist. -#define LOCK_FREE_CASES() \ +#define TRY_LOCK_FREE_CASE(n, type, ptr) \ + case n: \ + if (IS_LOCK_FREE_##n(ptr)) { \ + LOCK_FREE_ACTION(type); \ + } \ + break; +#ifdef __SIZEOF_INT128__ +#define TRY_LOCK_FREE_CASE_16(p) TRY_LOCK_FREE_CASE(16, __uint128_t, p) +#else +#define TRY_LOCK_FREE_CASE_16(p) /* __uint128_t not available */ +#endif + +#define LOCK_FREE_CASES(ptr) \ do { \ switch (size) { \ - case 1: \ - if (IS_LOCK_FREE_1) { \ - LOCK_FREE_ACTION(uint8_t); \ - } \ - break; \ - case 2: \ - if (IS_LOCK_FREE_2) { \ - LOCK_FREE_ACTION(uint16_t); \ - } \ - break; \ - case 4: \ - if (IS_LOCK_FREE_4) { \ - LOCK_FREE_ACTION(uint32_t); \ - } \ - break; \ - case 8: \ - if (IS_LOCK_FREE_8) { \ - LOCK_FREE_ACTION(uint64_t); \ - } \ - break; \ - case 16: \ - if (IS_LOCK_FREE_16) { \ - /* FIXME: __uint128_t isn't available on 32 bit platforms. \ - LOCK_FREE_ACTION(__uint128_t);*/ \ - } \ + TRY_LOCK_FREE_CASE(1, uint8_t, ptr) \ + TRY_LOCK_FREE_CASE(2, uint16_t, ptr) \ + TRY_LOCK_FREE_CASE(4, uint32_t, ptr) \ + TRY_LOCK_FREE_CASE(8, uint64_t, ptr) \ + TRY_LOCK_FREE_CASE_16(ptr) /* __uint128_t may not be supported */ \ + default: \ break; \ } \ } while (0) +/// Whether atomic operations for the given size (and alignment) are lock-free. +bool __atomic_is_lock_free_c(size_t size, void *ptr) { +#define LOCK_FREE_ACTION(type) return true; + LOCK_FREE_CASES(ptr); +#undef LOCK_FREE_ACTION + return false; +} + /// An atomic load operation. This is atomic with respect to the source /// pointer only. void __atomic_load_c(int size, void *src, void *dest, int model) { #define LOCK_FREE_ACTION(type) \ *((type *)dest) = __c11_atomic_load((_Atomic(type) *)src, model); \ return; - LOCK_FREE_CASES(); + LOCK_FREE_CASES(src); #undef LOCK_FREE_ACTION Lock *l = lock_for_pointer(src); lock(l); @@ -182,7 +187,7 @@ void __atomic_store_c(int size, void *dest, void *src, int model) { #define LOCK_FREE_ACTION(type) \ __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model); \ return; - LOCK_FREE_CASES(); + LOCK_FREE_CASES(dest); #undef LOCK_FREE_ACTION Lock *l = lock_for_pointer(dest); lock(l); @@ -201,7 +206,7 @@ int __atomic_compare_exchange_c(int size, void *ptr, void *expected, return __c11_atomic_compare_exchange_strong( \ (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \ failure) - LOCK_FREE_CASES(); + LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION Lock *l = lock_for_pointer(ptr); lock(l); @@ -222,7 +227,7 @@ void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { *(type *)old = \ __c11_atomic_exchange((_Atomic(type) *)ptr, *(type *)val, model); \ return; - LOCK_FREE_CASES(); + LOCK_FREE_CASES(ptr); #undef LOCK_FREE_ACTION Lock *l = lock_for_pointer(ptr); lock(l); @@ -252,7 +257,7 @@ void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { #define OPTIMISED_CASE(n, lockfree, type) \ type __atomic_load_##n(type *src, int model) { \ - if (lockfree) \ + if (lockfree(src)) \ return __c11_atomic_load((_Atomic(type) *)src, model); \ Lock *l = lock_for_pointer(src); \ lock(l); \ @@ -265,7 +270,7 @@ OPTIMISED_CASES #define OPTIMISED_CASE(n, lockfree, type) \ void __atomic_store_##n(type *dest, type val, int model) { \ - if (lockfree) { \ + if (lockfree(dest)) { \ __c11_atomic_store((_Atomic(type) *)dest, val, model); \ return; \ } \ @@ -280,7 +285,7 @@ OPTIMISED_CASES #define OPTIMISED_CASE(n, lockfree, type) \ type __atomic_exchange_##n(type *dest, type val, int model) { \ - if (lockfree) \ + if (lockfree(dest)) \ return __c11_atomic_exchange((_Atomic(type) *)dest, val, model); \ Lock *l = lock_for_pointer(dest); \ lock(l); \ @@ -293,9 +298,9 @@ OPTIMISED_CASES #undef OPTIMISED_CASE #define OPTIMISED_CASE(n, lockfree, type) \ - int __atomic_compare_exchange_##n(type *ptr, type *expected, type desired, \ - int success, int failure) { \ - if (lockfree) \ + bool __atomic_compare_exchange_##n(type *ptr, type *expected, type desired, \ + int success, int failure) { \ + if (lockfree(ptr)) \ return __c11_atomic_compare_exchange_strong( \ (_Atomic(type) *)ptr, expected, desired, success, failure); \ Lock *l = lock_for_pointer(ptr); \ @@ -303,11 +308,11 @@ OPTIMISED_CASES if (*ptr == *expected) { \ *ptr = desired; \ unlock(l); \ - return 1; \ + return true; \ } \ *expected = *ptr; \ unlock(l); \ - return 0; \ + return false; \ } OPTIMISED_CASES #undef OPTIMISED_CASE @@ -317,7 +322,7 @@ OPTIMISED_CASES //////////////////////////////////////////////////////////////////////////////// #define ATOMIC_RMW(n, lockfree, type, opname, op) \ type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) { \ - if (lockfree) \ + if (lockfree(ptr)) \ return __c11_atomic_fetch_##opname((_Atomic(type) *)ptr, val, model); \ Lock *l = lock_for_pointer(ptr); \ lock(l); \ diff --git a/system/lib/compiler-rt/lib/builtins/clear_cache.c b/system/lib/compiler-rt/lib/builtins/clear_cache.c index e83e21254e852..5a443ddd4b03a 100644 --- a/system/lib/compiler-rt/lib/builtins/clear_cache.c +++ b/system/lib/compiler-rt/lib/builtins/clear_cache.c @@ -33,7 +33,7 @@ uintptr_t GetCurrentProcess(void); #include #endif -#if defined(__OpenBSD__) && defined(__mips__) +#if defined(__OpenBSD__) && (defined(__arm__) || defined(__mips__)) // clang-format off #include #include @@ -46,6 +46,11 @@ uintptr_t GetCurrentProcess(void); #include #endif +#if defined(__linux__) && defined(__riscv) +// to get platform-specific syscall definitions +#include +#endif + // The compiler generates calls to __clear_cache() when creating // trampoline functions on the stack for use with nested functions. // It is expected to invalidate the instruction cache for the @@ -58,7 +63,7 @@ void __clear_cache(void *start, void *end) { #elif defined(_WIN32) && (defined(__arm__) || defined(__aarch64__)) FlushInstructionCache(GetCurrentProcess(), start, end - start); #elif defined(__arm__) && !defined(__APPLE__) -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) struct arm_sync_icache_args arg; arg.addr = (uintptr_t)start; @@ -147,10 +152,23 @@ void __clear_cache(void *start, void *end) { for (uintptr_t dword = start_dword; dword < end_dword; dword += dword_size) __asm__ volatile("flush %0" : : "r"(dword)); +#elif defined(__riscv) && defined(__linux__) + // See: arch/riscv/include/asm/cacheflush.h, arch/riscv/kernel/sys_riscv.c + register void *start_reg __asm("a0") = start; + const register void *end_reg __asm("a1") = end; + // "0" means that we clear cache for all threads (SYS_RISCV_FLUSH_ICACHE_ALL) + const register long flags __asm("a2") = 0; + const register long syscall_nr __asm("a7") = __NR_riscv_flush_icache; + __asm __volatile("ecall" + : "=r"(start_reg) + : "r"(start_reg), "r"(end_reg), "r"(flags), "r"(syscall_nr)); + assert(start_reg == 0 && "Cache flush syscall failed."); #else #if __APPLE__ // On Darwin, sys_icache_invalidate() provides this functionality sys_icache_invalidate(start, end - start); +#elif defined(__ve__) + __asm__ volatile("fencec 2"); #else compilerrt_abort(); #endif diff --git a/system/lib/compiler-rt/lib/builtins/clzdi2.c b/system/lib/compiler-rt/lib/builtins/clzdi2.c index a0bacb2ae39ea..12c17982a5cb1 100644 --- a/system/lib/compiler-rt/lib/builtins/clzdi2.c +++ b/system/lib/compiler-rt/lib/builtins/clzdi2.c @@ -21,15 +21,15 @@ // ctz instruction, gcc resolves __builtin_clz to __clzdi2 rather than // __clzsi2, leading to infinite recursion. #define __builtin_clz(a) __clzsi2(a) -extern si_int __clzsi2(si_int); +extern int __clzsi2(si_int); #endif // Precondition: a != 0 -COMPILER_RT_ABI si_int __clzdi2(di_int a) { +COMPILER_RT_ABI int __clzdi2(di_int a) { dwords x; x.all = a; const si_int f = -(x.s.high == 0); - return __builtin_clz((x.s.high & ~f) | (x.s.low & f)) + + return clzsi((x.s.high & ~f) | (x.s.low & f)) + (f & ((si_int)(sizeof(si_int) * CHAR_BIT))); } diff --git a/system/lib/compiler-rt/lib/builtins/clzsi2.c b/system/lib/compiler-rt/lib/builtins/clzsi2.c index 3f9f27f413315..d75f56d937b07 100644 --- a/system/lib/compiler-rt/lib/builtins/clzsi2.c +++ b/system/lib/compiler-rt/lib/builtins/clzsi2.c @@ -16,7 +16,7 @@ // Precondition: a != 0 -COMPILER_RT_ABI si_int __clzsi2(si_int a) { +COMPILER_RT_ABI int __clzsi2(si_int a) { su_int x = (su_int)a; si_int t = ((x & 0xFFFF0000) == 0) << 4; // if (x is small) t = 16 else 0 x >>= 16 - t; // x = [0 - 0xFFFF] diff --git a/system/lib/compiler-rt/lib/builtins/clzti2.c b/system/lib/compiler-rt/lib/builtins/clzti2.c index 0c787104caa2a..25d30119f271c 100644 --- a/system/lib/compiler-rt/lib/builtins/clzti2.c +++ b/system/lib/compiler-rt/lib/builtins/clzti2.c @@ -18,7 +18,7 @@ // Precondition: a != 0 -COMPILER_RT_ABI si_int __clzti2(ti_int a) { +COMPILER_RT_ABI int __clzti2(ti_int a) { twords x; x.all = a; const di_int f = -(x.s.high == 0); diff --git a/system/lib/compiler-rt/lib/builtins/cpu_model.c b/system/lib/compiler-rt/lib/builtins/cpu_model.c index fb619037d398c..51bedd98c3d30 100644 --- a/system/lib/compiler-rt/lib/builtins/cpu_model.c +++ b/system/lib/compiler-rt/lib/builtins/cpu_model.c @@ -8,10 +8,21 @@ // // This file is based on LLVM's lib/Support/Host.cpp. // It implements the operating system Host concept and builtin -// __cpu_model for the compiler_rt library, for x86 only. +// __cpu_model for the compiler_rt library for x86 and +// __aarch64_have_lse_atomics for AArch64. // //===----------------------------------------------------------------------===// +#if defined(HAVE_INIT_PRIORITY) +#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101)) +#elif __has_attribute(__constructor__) +#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__)) +#else +// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that +// this runs during initialization. +#define CONSTRUCTOR_ATTRIBUTE +#endif + #if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || \ defined(_M_X64)) && \ (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)) @@ -57,6 +68,7 @@ enum ProcessorTypes { INTEL_GOLDMONT, INTEL_GOLDMONT_PLUS, INTEL_TREMONT, + AMDFAM19H, CPU_TYPE_MAX }; @@ -82,6 +94,11 @@ enum ProcessorSubtypes { INTEL_COREI7_ICELAKE_SERVER, AMDFAM17H_ZNVER2, INTEL_COREI7_CASCADELAKE, + INTEL_COREI7_TIGERLAKE, + INTEL_COREI7_COOPERLAKE, + INTEL_COREI7_SAPPHIRERAPIDS, + INTEL_COREI7_ALDERLAKE, + AMDFAM19H_ZNVER3, CPU_SUBTYPE_MAX }; @@ -122,7 +139,9 @@ enum ProcessorFeatures { FEATURE_VPCLMULQDQ, FEATURE_AVX512VNNI, FEATURE_AVX512BITALG, - FEATURE_AVX512BF16 + FEATURE_AVX512BF16, + FEATURE_AVX512VP2INTERSECT, + CPU_FEATURE_MAX }; // The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max). @@ -268,13 +287,17 @@ static void detectX86FamilyModel(unsigned EAX, unsigned *Family, } } -static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, - unsigned Brand_id, - unsigned Features, - unsigned Features2, unsigned *Type, - unsigned *Subtype) { - if (Brand_id != 0) - return; +static const char * +getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, + const unsigned *Features, + unsigned *Type, unsigned *Subtype) { +#define testFeature(F) \ + (Features[F / 32] & (1 << (F % 32))) != 0 + + // We select CPU strings to match the code in Host.cpp, but we don't use them + // in compiler-rt. + const char *CPU = 0; + switch (Family) { case 6: switch (Model) { @@ -285,13 +308,17 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, // 0Fh. All processors are manufactured using the 65 nm process. case 0x16: // Intel Celeron processor model 16h. All processors are // manufactured using the 65 nm process + CPU = "core2"; + *Type = INTEL_CORE2; + break; case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model // 17h. All processors are manufactured using the 45 nm process. // // 45nm: Penryn , Wolfdale, Yorkfield (XE) case 0x1d: // Intel Xeon processor MP. All processors are manufactured using // the 45 nm process. - *Type = INTEL_CORE2; // "penryn" + CPU = "penryn"; + *Type = INTEL_CORE2; break; case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 45 nm process. @@ -299,25 +326,29 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, // As found in a Summer 2010 model iMac. case 0x1f: case 0x2e: // Nehalem EX - *Type = INTEL_COREI7; // "nehalem" + CPU = "nehalem"; + *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_NEHALEM; break; case 0x25: // Intel Core i7, laptop version. case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 32 nm process. case 0x2f: // Westmere EX - *Type = INTEL_COREI7; // "westmere" + CPU = "westmere"; + *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_WESTMERE; break; case 0x2a: // Intel Core i7 processor. All processors are manufactured // using the 32 nm process. case 0x2d: - *Type = INTEL_COREI7; //"sandybridge" + CPU = "sandybridge"; + *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_SANDYBRIDGE; break; case 0x3a: case 0x3e: // Ivy Bridge EP - *Type = INTEL_COREI7; // "ivybridge" + CPU = "ivybridge"; + *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_IVYBRIDGE; break; @@ -326,7 +357,8 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x3f: case 0x45: case 0x46: - *Type = INTEL_COREI7; // "haswell" + CPU = "haswell"; + *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_HASWELL; break; @@ -335,7 +367,8 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x47: case 0x4f: case 0x56: - *Type = INTEL_COREI7; // "broadwell" + CPU = "broadwell"; + *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_BROADWELL; break; @@ -344,37 +377,56 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x5e: // Skylake desktop case 0x8e: // Kaby Lake mobile case 0x9e: // Kaby Lake desktop - *Type = INTEL_COREI7; // "skylake" + case 0xa5: // Comet Lake-H/S + case 0xa6: // Comet Lake-U + CPU = "skylake"; + *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_SKYLAKE; break; // Skylake Xeon: case 0x55: *Type = INTEL_COREI7; - if (Features2 & (1 << (FEATURE_AVX512VNNI - 32))) - *Subtype = INTEL_COREI7_CASCADELAKE; // "cascadelake" - else - *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" + if (testFeature(FEATURE_AVX512BF16)) { + CPU = "cooperlake"; + *Subtype = INTEL_COREI7_COOPERLAKE; + } else if (testFeature(FEATURE_AVX512VNNI)) { + CPU = "cascadelake"; + *Subtype = INTEL_COREI7_CASCADELAKE; + } else { + CPU = "skylake-avx512"; + *Subtype = INTEL_COREI7_SKYLAKE_AVX512; + } break; // Cannonlake: case 0x66: + CPU = "cannonlake"; *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_CANNONLAKE; // "cannonlake" + *Subtype = INTEL_COREI7_CANNONLAKE; break; // Icelake: case 0x7d: case 0x7e: + CPU = "icelake-client"; *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_ICELAKE_CLIENT; // "icelake-client" + *Subtype = INTEL_COREI7_ICELAKE_CLIENT; break; // Icelake Xeon: case 0x6a: case 0x6c: + CPU = "icelake-server"; *Type = INTEL_COREI7; - *Subtype = INTEL_COREI7_ICELAKE_SERVER; // "icelake-server" + *Subtype = INTEL_COREI7_ICELAKE_SERVER; + break; + + // Sapphire Rapids: + case 0x8f: + CPU = "sapphirerapids"; + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_SAPPHIRERAPIDS; break; case 0x1c: // Most 45 nm Intel Atom processors @@ -382,8 +434,9 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x27: // 32 nm Atom Medfield case 0x35: // 32 nm Atom Midview case 0x36: // 32 nm Atom Midview + CPU = "bonnell"; *Type = INTEL_BONNELL; - break; // "bonnell" + break; // Atom Silvermont codes from the Intel software optimization guide. case 0x37: @@ -392,26 +445,32 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x5a: case 0x5d: case 0x4c: // really airmont + CPU = "silvermont"; *Type = INTEL_SILVERMONT; - break; // "silvermont" + break; // Goldmont: case 0x5c: // Apollo Lake case 0x5f: // Denverton + CPU = "goldmont"; *Type = INTEL_GOLDMONT; break; // "goldmont" case 0x7a: + CPU = "goldmont-plus"; *Type = INTEL_GOLDMONT_PLUS; break; case 0x86: + CPU = "tremont"; *Type = INTEL_TREMONT; break; case 0x57: - *Type = INTEL_KNL; // knl + CPU = "knl"; + *Type = INTEL_KNL; break; case 0x85: - *Type = INTEL_KNM; // knm + CPU = "knm"; + *Type = INTEL_KNM; break; default: // Unknown family 6 CPU. @@ -421,17 +480,22 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, default: break; // Unknown. } + + return CPU; } -static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, - unsigned Features, unsigned Features2, - unsigned *Type, unsigned *Subtype) { - // FIXME: this poorly matches the generated SubtargetFeatureKV table. There - // appears to be no way to generate the wide variety of AMD-specific targets - // from the information returned from CPUID. +static const char * +getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, + const unsigned *Features, + unsigned *Type, unsigned *Subtype) { + // We select CPU strings to match the code in Host.cpp, but we don't use them + // in compiler-rt. + const char *CPU = 0; + switch (Family) { case 16: - *Type = AMDFAM10H; // "amdfam10" + CPU = "amdfam10"; + *Type = AMDFAM10H; switch (Model) { case 2: *Subtype = AMDFAM10H_BARCELONA; @@ -445,60 +509,70 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, } break; case 20: + CPU = "btver1"; *Type = AMD_BTVER1; - break; // "btver1"; + break; case 21: + CPU = "bdver1"; *Type = AMDFAM15H; if (Model >= 0x60 && Model <= 0x7f) { + CPU = "bdver4"; *Subtype = AMDFAM15H_BDVER4; - break; // "bdver4"; 60h-7Fh: Excavator + break; // 60h-7Fh: Excavator } if (Model >= 0x30 && Model <= 0x3f) { + CPU = "bdver3"; *Subtype = AMDFAM15H_BDVER3; - break; // "bdver3"; 30h-3Fh: Steamroller + break; // 30h-3Fh: Steamroller } if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) { + CPU = "bdver2"; *Subtype = AMDFAM15H_BDVER2; - break; // "bdver2"; 02h, 10h-1Fh: Piledriver + break; // 02h, 10h-1Fh: Piledriver } if (Model <= 0x0f) { *Subtype = AMDFAM15H_BDVER1; - break; // "bdver1"; 00h-0Fh: Bulldozer + break; // 00h-0Fh: Bulldozer } break; case 22: + CPU = "btver2"; *Type = AMD_BTVER2; - break; // "btver2" + break; case 23: + CPU = "znver1"; *Type = AMDFAM17H; if ((Model >= 0x30 && Model <= 0x3f) || Model == 0x71) { + CPU = "znver2"; *Subtype = AMDFAM17H_ZNVER2; - break; // "znver2"; 30h-3fh, 71h: Zen2 + break; // 30h-3fh, 71h: Zen2 } if (Model <= 0x0f) { *Subtype = AMDFAM17H_ZNVER1; - break; // "znver1"; 00h-0Fh: Zen1 + break; // 00h-0Fh: Zen1 + } + break; + case 25: + CPU = "znver3"; + *Type = AMDFAM19H; + if (Model <= 0x0f) { + *Subtype = AMDFAM19H_ZNVER3; + break; // 00h-0Fh: Zen3 } break; default: - break; // "generic" + break; // Unknown AMD CPU. } + + return CPU; } static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, - unsigned *FeaturesOut, - unsigned *Features2Out) { - unsigned Features = 0; - unsigned Features2 = 0; + unsigned *Features) { unsigned EAX, EBX; #define setFeature(F) \ - do { \ - if (F < 32) \ - Features |= 1U << (F & 0x1f); \ - else if (F < 64) \ - Features2 |= 1U << ((F - 32) & 0x1f); \ - } while (0) + Features[F / 32] |= 1U << (F % 32) if ((EDX >> 15) & 1) setFeature(FEATURE_CMOV); @@ -590,6 +664,8 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, setFeature(FEATURE_AVX5124VNNIW); if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) setFeature(FEATURE_AVX5124FMAPS); + if (HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save) + setFeature(FEATURE_AVX512VP2INTERSECT); bool HasLeaf7Subleaf1 = MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX); @@ -607,22 +683,9 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, setFeature(FEATURE_XOP); if (HasExtLeaf1 && ((ECX >> 16) & 1)) setFeature(FEATURE_FMA4); - - *FeaturesOut = Features; - *Features2Out = Features2; #undef setFeature } -#if defined(HAVE_INIT_PRIORITY) -#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101)) -#elif __has_attribute(__constructor__) -#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__)) -#else -// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that -// this runs during initialization. -#define CONSTRUCTOR_ATTRIBUTE -#endif - #ifndef _WIN32 __attribute__((visibility("hidden"))) #endif @@ -641,7 +704,7 @@ struct __processor_model { #ifndef _WIN32 __attribute__((visibility("hidden"))) #endif -unsigned int __cpu_features2; +unsigned int __cpu_features2 = 0; // A constructor function that is sets __cpu_model and __cpu_features2 with // the right values. This needs to run only once. This constructor is @@ -653,40 +716,38 @@ int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) { unsigned EAX, EBX, ECX, EDX; unsigned MaxLeaf = 5; unsigned Vendor; - unsigned Model, Family, Brand_id; - unsigned Features = 0; - unsigned Features2 = 0; + unsigned Model, Family; + unsigned Features[(CPU_FEATURE_MAX + 31) / 32] = {0}; // This function needs to run just once. if (__cpu_model.__cpu_vendor) return 0; - if (!isCpuIdSupported()) - return -1; - - // Assume cpuid insn present. Run in level 0 to get vendor id. - if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) { + if (!isCpuIdSupported() || + getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) { __cpu_model.__cpu_vendor = VENDOR_OTHER; return -1; } + getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); detectX86FamilyModel(EAX, &Family, &Model); - Brand_id = EBX & 0xff; // Find available features. - getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2); - __cpu_model.__cpu_features[0] = Features; - __cpu_features2 = Features2; + getAvailableFeatures(ECX, EDX, MaxLeaf, &Features[0]); + + assert((sizeof(Features)/sizeof(Features[0])) == 2); + __cpu_model.__cpu_features[0] = Features[0]; + __cpu_features2 = Features[1]; if (Vendor == SIG_INTEL) { // Get CPU type. - getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, - Features2, &(__cpu_model.__cpu_type), + getIntelProcessorTypeAndSubtype(Family, Model, &Features[0], + &(__cpu_model.__cpu_type), &(__cpu_model.__cpu_subtype)); __cpu_model.__cpu_vendor = VENDOR_INTEL; } else if (Vendor == SIG_AMD) { // Get CPU type. - getAMDProcessorTypeAndSubtype(Family, Model, Features, Features2, + getAMDProcessorTypeAndSubtype(Family, Model, &Features[0], &(__cpu_model.__cpu_type), &(__cpu_model.__cpu_subtype)); __cpu_model.__cpu_vendor = VENDOR_AMD; @@ -699,5 +760,24 @@ int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) { return 0; } - +#elif defined(__aarch64__) +// LSE support detection for out-of-line atomics +// using HWCAP and Auxiliary vector +_Bool __aarch64_have_lse_atomics + __attribute__((visibility("hidden"), nocommon)); +#if defined(__has_include) +#if __has_include() +#include +#ifndef AT_HWCAP +#define AT_HWCAP 16 +#endif +#ifndef HWCAP_ATOMICS +#define HWCAP_ATOMICS (1 << 8) #endif +static void CONSTRUCTOR_ATTRIBUTE init_have_lse_atomics(void) { + unsigned long hwcap = getauxval(AT_HWCAP); + __aarch64_have_lse_atomics = (hwcap & HWCAP_ATOMICS) != 0; +} +#endif // defined(__has_include) +#endif // __has_include() +#endif // defined(__aarch64__) diff --git a/system/lib/compiler-rt/lib/builtins/ctzdi2.c b/system/lib/compiler-rt/lib/builtins/ctzdi2.c index 9384aa6055a11..26c908d876ac4 100644 --- a/system/lib/compiler-rt/lib/builtins/ctzdi2.c +++ b/system/lib/compiler-rt/lib/builtins/ctzdi2.c @@ -21,15 +21,15 @@ // ctz instruction, gcc resolves __builtin_ctz to __ctzdi2 rather than // __ctzsi2, leading to infinite recursion. #define __builtin_ctz(a) __ctzsi2(a) -extern si_int __ctzsi2(si_int); +extern int __ctzsi2(si_int); #endif // Precondition: a != 0 -COMPILER_RT_ABI si_int __ctzdi2(di_int a) { +COMPILER_RT_ABI int __ctzdi2(di_int a) { dwords x; x.all = a; const si_int f = -(x.s.low == 0); - return __builtin_ctz((x.s.high & f) | (x.s.low & ~f)) + + return ctzsi((x.s.high & f) | (x.s.low & ~f)) + (f & ((si_int)(sizeof(si_int) * CHAR_BIT))); } diff --git a/system/lib/compiler-rt/lib/builtins/ctzsi2.c b/system/lib/compiler-rt/lib/builtins/ctzsi2.c index 09c6863b74e3a..ed95c60579339 100644 --- a/system/lib/compiler-rt/lib/builtins/ctzsi2.c +++ b/system/lib/compiler-rt/lib/builtins/ctzsi2.c @@ -16,7 +16,7 @@ // Precondition: a != 0 -COMPILER_RT_ABI si_int __ctzsi2(si_int a) { +COMPILER_RT_ABI int __ctzsi2(si_int a) { su_int x = (su_int)a; si_int t = ((x & 0x0000FFFF) == 0) << 4; // if (x has no small bits) t = 16 else 0 diff --git a/system/lib/compiler-rt/lib/builtins/ctzti2.c b/system/lib/compiler-rt/lib/builtins/ctzti2.c index 2a1312c8437de..fb136d0de1c0d 100644 --- a/system/lib/compiler-rt/lib/builtins/ctzti2.c +++ b/system/lib/compiler-rt/lib/builtins/ctzti2.c @@ -18,7 +18,7 @@ // Precondition: a != 0 -COMPILER_RT_ABI si_int __ctzti2(ti_int a) { +COMPILER_RT_ABI int __ctzti2(ti_int a) { twords x; x.all = a; const di_int f = -(x.s.low == 0); diff --git a/system/lib/compiler-rt/lib/builtins/divdf3.c b/system/lib/compiler-rt/lib/builtins/divdf3.c index 1dea3b534f5ae..4c11759e0c4a7 100644 --- a/system/lib/compiler-rt/lib/builtins/divdf3.c +++ b/system/lib/compiler-rt/lib/builtins/divdf3.c @@ -9,197 +9,16 @@ // This file implements double-precision soft-float division // with the IEEE-754 default rounding (to nearest, ties to even). // -// For simplicity, this implementation currently flushes denormals to zero. -// It should be a fairly straightforward exercise to implement gradual -// underflow with correct rounding. -// //===----------------------------------------------------------------------===// #define DOUBLE_PRECISION -#include "fp_lib.h" - -COMPILER_RT_ABI fp_t __divdf3(fp_t a, fp_t b) { - - const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; - const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; - const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit; - - rep_t aSignificand = toRep(a) & significandMask; - rep_t bSignificand = toRep(b) & significandMask; - int scale = 0; - - // Detect if a or b is zero, denormal, infinity, or NaN. - if (aExponent - 1U >= maxExponent - 1U || - bExponent - 1U >= maxExponent - 1U) { - - const rep_t aAbs = toRep(a) & absMask; - const rep_t bAbs = toRep(b) & absMask; - - // NaN / anything = qNaN - if (aAbs > infRep) - return fromRep(toRep(a) | quietBit); - // anything / NaN = qNaN - if (bAbs > infRep) - return fromRep(toRep(b) | quietBit); - - if (aAbs == infRep) { - // infinity / infinity = NaN - if (bAbs == infRep) - return fromRep(qnanRep); - // infinity / anything else = +/- infinity - else - return fromRep(aAbs | quotientSign); - } - - // anything else / infinity = +/- 0 - if (bAbs == infRep) - return fromRep(quotientSign); - - if (!aAbs) { - // zero / zero = NaN - if (!bAbs) - return fromRep(qnanRep); - // zero / anything else = +/- zero - else - return fromRep(quotientSign); - } - // anything else / zero = +/- infinity - if (!bAbs) - return fromRep(infRep | quotientSign); - - // One or both of a or b is denormal. The other (if applicable) is a - // normal number. Renormalize one or both of a and b, and set scale to - // include the necessary exponent adjustment. - if (aAbs < implicitBit) - scale += normalize(&aSignificand); - if (bAbs < implicitBit) - scale -= normalize(&bSignificand); - } - - // Set the implicit significand bit. If we fell through from the - // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything. - aSignificand |= implicitBit; - bSignificand |= implicitBit; - int quotientExponent = aExponent - bExponent + scale; - - // Align the significand of b as a Q31 fixed-point number in the range - // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax - // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This - // is accurate to about 3.5 binary digits. - const uint32_t q31b = bSignificand >> 21; - uint32_t recip32 = UINT32_C(0x7504f333) - q31b; - // 0x7504F333 / 2^32 + 1 = 3/4 + 1/sqrt(2) - - // Now refine the reciprocal estimate using a Newton-Raphson iteration: - // - // x1 = x0 * (2 - x0 * b) - // - // This doubles the number of correct binary digits in the approximation - // with each iteration. - uint32_t correction32; - correction32 = -((uint64_t)recip32 * q31b >> 32); - recip32 = (uint64_t)recip32 * correction32 >> 31; - correction32 = -((uint64_t)recip32 * q31b >> 32); - recip32 = (uint64_t)recip32 * correction32 >> 31; - correction32 = -((uint64_t)recip32 * q31b >> 32); - recip32 = (uint64_t)recip32 * correction32 >> 31; - - // The reciprocal may have overflowed to zero if the upper half of b is - // exactly 1.0. This would sabatoge the full-width final stage of the - // computation that follows, so we adjust the reciprocal down by one bit. - recip32--; - - // We need to perform one more iteration to get us to 56 binary digits. - // The last iteration needs to happen with extra precision. - const uint32_t q63blo = bSignificand << 11; - uint64_t correction, reciprocal; - correction = -((uint64_t)recip32 * q31b + ((uint64_t)recip32 * q63blo >> 32)); - uint32_t cHi = correction >> 32; - uint32_t cLo = correction; - reciprocal = (uint64_t)recip32 * cHi + ((uint64_t)recip32 * cLo >> 32); - - // Adjust the final 64-bit reciprocal estimate downward to ensure that it is - // strictly smaller than the infinitely precise exact reciprocal. Because - // the computation of the Newton-Raphson step is truncating at every step, - // this adjustment is small; most of the work is already done. - reciprocal -= 2; - - // The numerical reciprocal is accurate to within 2^-56, lies in the - // interval [0.5, 1.0), and is strictly smaller than the true reciprocal - // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b - // in Q53 with the following properties: - // - // 1. q < a/b - // 2. q is in the interval [0.5, 2.0) - // 3. The error in q is bounded away from 2^-53 (actually, we have a - // couple of bits to spare, but this is all we need). - - // We need a 64 x 64 multiply high to compute q, which isn't a basic - // operation in C, so we need to be a little bit fussy. - rep_t quotient, quotientLo; - wideMultiply(aSignificand << 2, reciprocal, "ient, "ientLo); - - // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). - // In either case, we are going to compute a residual of the form - // - // r = a - q*b - // - // We know from the construction of q that r satisfies: - // - // 0 <= r < ulp(q)*b - // - // If r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we - // already have the correct result. The exact halfway case cannot occur. - // We also take this time to right shift quotient if it falls in the [1,2) - // range and adjust the exponent accordingly. - rep_t residual; - if (quotient < (implicitBit << 1)) { - residual = (aSignificand << 53) - quotient * bSignificand; - quotientExponent--; - } else { - quotient >>= 1; - residual = (aSignificand << 52) - quotient * bSignificand; - } - - const int writtenExponent = quotientExponent + exponentBias; - if (writtenExponent >= maxExponent) { - // If we have overflowed the exponent, return infinity. - return fromRep(infRep | quotientSign); - } +#define NUMBER_OF_HALF_ITERATIONS 3 +#define NUMBER_OF_FULL_ITERATIONS 1 - else if (writtenExponent < 1) { - if (writtenExponent == 0) { - // Check whether the rounded result is normal. - const bool round = (residual << 1) > bSignificand; - // Clear the implicit bit. - rep_t absResult = quotient & significandMask; - // Round. - absResult += round; - if (absResult & ~significandMask) { - // The rounded result is normal; return it. - return fromRep(absResult | quotientSign); - } - } - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return fromRep(quotientSign); - } +#include "fp_div_impl.inc" - else { - const bool round = (residual << 1) > bSignificand; - // Clear the implicit bit. - rep_t absResult = quotient & significandMask; - // Insert the exponent. - absResult |= (rep_t)writtenExponent << significandBits; - // Round. - absResult += round; - // Insert the sign and return. - const double result = fromRep(absResult | quotientSign); - return result; - } -} +COMPILER_RT_ABI fp_t __divdf3(fp_t a, fp_t b) { return __divXf3__(a, b); } #if defined(__ARM_EABI__) #if defined(COMPILER_RT_ARMHF_TARGET) diff --git a/system/lib/compiler-rt/lib/builtins/divdi3.c b/system/lib/compiler-rt/lib/builtins/divdi3.c index ee08d6557783c..d71e138d995c7 100644 --- a/system/lib/compiler-rt/lib/builtins/divdi3.c +++ b/system/lib/compiler-rt/lib/builtins/divdi3.c @@ -14,12 +14,9 @@ // Returns: a / b -COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b) { - const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; - di_int s_a = a >> bits_in_dword_m1; // s_a = a < 0 ? -1 : 0 - di_int s_b = b >> bits_in_dword_m1; // s_b = b < 0 ? -1 : 0 - a = (a ^ s_a) - s_a; // negate if s_a == -1 - b = (b ^ s_b) - s_b; // negate if s_b == -1 - s_a ^= s_b; // sign of quotient - return (__udivmoddi4(a, b, (du_int *)0) ^ s_a) - s_a; // negate if s_a == -1 -} +#define fixint_t di_int +#define fixuint_t du_int +#define COMPUTE_UDIV(a, b) __udivmoddi4((a), (b), (du_int *)0) +#include "int_div_impl.inc" + +COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b) { return __divXi3(a, b); } diff --git a/system/lib/compiler-rt/lib/builtins/divmoddi4.c b/system/lib/compiler-rt/lib/builtins/divmoddi4.c index 7f333510c0034..e7cbbb1aaa304 100644 --- a/system/lib/compiler-rt/lib/builtins/divmoddi4.c +++ b/system/lib/compiler-rt/lib/builtins/divmoddi4.c @@ -15,7 +15,14 @@ // Returns: a / b, *rem = a % b COMPILER_RT_ABI di_int __divmoddi4(di_int a, di_int b, di_int *rem) { - di_int d = __divdi3(a, b); - *rem = a - (d * b); - return d; + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s_a = a >> bits_in_dword_m1; // s_a = a < 0 ? -1 : 0 + di_int s_b = b >> bits_in_dword_m1; // s_b = b < 0 ? -1 : 0 + a = (a ^ s_a) - s_a; // negate if s_a == -1 + b = (b ^ s_b) - s_b; // negate if s_b == -1 + s_b ^= s_a; // sign of quotient + du_int r; + di_int q = (__udivmoddi4(a, b, &r) ^ s_b) - s_b; // negate if s_b == -1 + *rem = (r ^ s_a) - s_a; // negate if s_a == -1 + return q; } diff --git a/system/lib/compiler-rt/lib/builtins/divmodsi4.c b/system/lib/compiler-rt/lib/builtins/divmodsi4.c index 402eed22fe7a0..a85e2993b4e9b 100644 --- a/system/lib/compiler-rt/lib/builtins/divmodsi4.c +++ b/system/lib/compiler-rt/lib/builtins/divmodsi4.c @@ -16,7 +16,14 @@ // Returns: a / b, *rem = a % b COMPILER_RT_ABI si_int __divmodsi4(si_int a, si_int b, si_int *rem) { - si_int d = __divsi3(a, b); - *rem = a - (d * b); - return d; + const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1; + si_int s_a = a >> bits_in_word_m1; // s_a = a < 0 ? -1 : 0 + si_int s_b = b >> bits_in_word_m1; // s_b = b < 0 ? -1 : 0 + a = (a ^ s_a) - s_a; // negate if s_a == -1 + b = (b ^ s_b) - s_b; // negate if s_b == -1 + s_b ^= s_a; // sign of quotient + su_int r; + si_int q = (__udivmodsi4(a, b, &r) ^ s_b) - s_b; // negate if s_b == -1 + *rem = (r ^ s_a) - s_a; // negate if s_a == -1 + return q; } diff --git a/system/lib/compiler-rt/lib/builtins/divmodti4.c b/system/lib/compiler-rt/lib/builtins/divmodti4.c new file mode 100644 index 0000000000000..b243ba4ef8537 --- /dev/null +++ b/system/lib/compiler-rt/lib/builtins/divmodti4.c @@ -0,0 +1,32 @@ +//===-- divmodti4.c - Implement __divmodti4 -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __divmodti4 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +#ifdef CRT_HAS_128BIT + +// Returns: a / b, *rem = a % b + +COMPILER_RT_ABI ti_int __divmodti4(ti_int a, ti_int b, ti_int *rem) { + const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1; + ti_int s_a = a >> bits_in_tword_m1; // s_a = a < 0 ? -1 : 0 + ti_int s_b = b >> bits_in_tword_m1; // s_b = b < 0 ? -1 : 0 + a = (a ^ s_a) - s_a; // negate if s_a == -1 + b = (b ^ s_b) - s_b; // negate if s_b == -1 + s_b ^= s_a; // sign of quotient + tu_int r; + ti_int q = (__udivmodti4(a, b, &r) ^ s_b) - s_b; // negate if s_b == -1 + *rem = (r ^ s_a) - s_a; // negate if s_a == -1 + return q; +} + +#endif // CRT_HAS_128BIT diff --git a/system/lib/compiler-rt/lib/builtins/divsf3.c b/system/lib/compiler-rt/lib/builtins/divsf3.c index 593f93b45ac24..5744c015240b6 100644 --- a/system/lib/compiler-rt/lib/builtins/divsf3.c +++ b/system/lib/compiler-rt/lib/builtins/divsf3.c @@ -9,181 +9,17 @@ // This file implements single-precision soft-float division // with the IEEE-754 default rounding (to nearest, ties to even). // -// For simplicity, this implementation currently flushes denormals to zero. -// It should be a fairly straightforward exercise to implement gradual -// underflow with correct rounding. -// //===----------------------------------------------------------------------===// #define SINGLE_PRECISION -#include "fp_lib.h" - -COMPILER_RT_ABI fp_t __divsf3(fp_t a, fp_t b) { - - const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; - const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; - const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit; - - rep_t aSignificand = toRep(a) & significandMask; - rep_t bSignificand = toRep(b) & significandMask; - int scale = 0; - - // Detect if a or b is zero, denormal, infinity, or NaN. - if (aExponent - 1U >= maxExponent - 1U || - bExponent - 1U >= maxExponent - 1U) { - - const rep_t aAbs = toRep(a) & absMask; - const rep_t bAbs = toRep(b) & absMask; - - // NaN / anything = qNaN - if (aAbs > infRep) - return fromRep(toRep(a) | quietBit); - // anything / NaN = qNaN - if (bAbs > infRep) - return fromRep(toRep(b) | quietBit); - - if (aAbs == infRep) { - // infinity / infinity = NaN - if (bAbs == infRep) - return fromRep(qnanRep); - // infinity / anything else = +/- infinity - else - return fromRep(aAbs | quotientSign); - } - - // anything else / infinity = +/- 0 - if (bAbs == infRep) - return fromRep(quotientSign); - - if (!aAbs) { - // zero / zero = NaN - if (!bAbs) - return fromRep(qnanRep); - // zero / anything else = +/- zero - else - return fromRep(quotientSign); - } - // anything else / zero = +/- infinity - if (!bAbs) - return fromRep(infRep | quotientSign); - - // One or both of a or b is denormal. The other (if applicable) is a - // normal number. Renormalize one or both of a and b, and set scale to - // include the necessary exponent adjustment. - if (aAbs < implicitBit) - scale += normalize(&aSignificand); - if (bAbs < implicitBit) - scale -= normalize(&bSignificand); - } - - // Set the implicit significand bit. If we fell through from the - // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything. - aSignificand |= implicitBit; - bSignificand |= implicitBit; - int quotientExponent = aExponent - bExponent + scale; - // 0x7504F333 / 2^32 + 1 = 3/4 + 1/sqrt(2) - - // Align the significand of b as a Q31 fixed-point number in the range - // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax - // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This - // is accurate to about 3.5 binary digits. - uint32_t q31b = bSignificand << 8; - uint32_t reciprocal = UINT32_C(0x7504f333) - q31b; - - // Now refine the reciprocal estimate using a Newton-Raphson iteration: - // - // x1 = x0 * (2 - x0 * b) - // - // This doubles the number of correct binary digits in the approximation - // with each iteration. - uint32_t correction; - correction = -((uint64_t)reciprocal * q31b >> 32); - reciprocal = (uint64_t)reciprocal * correction >> 31; - correction = -((uint64_t)reciprocal * q31b >> 32); - reciprocal = (uint64_t)reciprocal * correction >> 31; - correction = -((uint64_t)reciprocal * q31b >> 32); - reciprocal = (uint64_t)reciprocal * correction >> 31; - - // Adust the final 32-bit reciprocal estimate downward to ensure that it is - // strictly smaller than the infinitely precise exact reciprocal. Because - // the computation of the Newton-Raphson step is truncating at every step, - // this adjustment is small; most of the work is already done. - reciprocal -= 2; - - // The numerical reciprocal is accurate to within 2^-28, lies in the - // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller - // than the true reciprocal of b. Multiplying a by this reciprocal thus - // gives a numerical q = a/b in Q24 with the following properties: - // - // 1. q < a/b - // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0) - // 3. The error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes - // from the fact that we truncate the product, and the 2^27 term - // is the error in the reciprocal of b scaled by the maximum - // possible value of a. As a consequence of this error bound, - // either q or nextafter(q) is the correctly rounded. - rep_t quotient = (uint64_t)reciprocal * (aSignificand << 1) >> 32; - - // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). - // In either case, we are going to compute a residual of the form - // - // r = a - q*b - // - // We know from the construction of q that r satisfies: - // - // 0 <= r < ulp(q)*b - // - // If r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we - // already have the correct result. The exact halfway case cannot occur. - // We also take this time to right shift quotient if it falls in the [1,2) - // range and adjust the exponent accordingly. - rep_t residual; - if (quotient < (implicitBit << 1)) { - residual = (aSignificand << 24) - quotient * bSignificand; - quotientExponent--; - } else { - quotient >>= 1; - residual = (aSignificand << 23) - quotient * bSignificand; - } - - const int writtenExponent = quotientExponent + exponentBias; - if (writtenExponent >= maxExponent) { - // If we have overflowed the exponent, return infinity. - return fromRep(infRep | quotientSign); - } +#define NUMBER_OF_HALF_ITERATIONS 0 +#define NUMBER_OF_FULL_ITERATIONS 3 +#define USE_NATIVE_FULL_ITERATIONS - else if (writtenExponent < 1) { - if (writtenExponent == 0) { - // Check whether the rounded result is normal. - const bool round = (residual << 1) > bSignificand; - // Clear the implicit bit. - rep_t absResult = quotient & significandMask; - // Round. - absResult += round; - if (absResult & ~significandMask) { - // The rounded result is normal; return it. - return fromRep(absResult | quotientSign); - } - } - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return fromRep(quotientSign); - } +#include "fp_div_impl.inc" - else { - const bool round = (residual << 1) > bSignificand; - // Clear the implicit bit. - rep_t absResult = quotient & significandMask; - // Insert the exponent. - absResult |= (rep_t)writtenExponent << significandBits; - // Round. - absResult += round; - // Insert the sign and return. - return fromRep(absResult | quotientSign); - } -} +COMPILER_RT_ABI fp_t __divsf3(fp_t a, fp_t b) { return __divXf3__(a, b); } #if defined(__ARM_EABI__) #if defined(COMPILER_RT_ARMHF_TARGET) diff --git a/system/lib/compiler-rt/lib/builtins/divsi3.c b/system/lib/compiler-rt/lib/builtins/divsi3.c index b97e11119f0eb..f514407477f33 100644 --- a/system/lib/compiler-rt/lib/builtins/divsi3.c +++ b/system/lib/compiler-rt/lib/builtins/divsi3.c @@ -14,21 +14,16 @@ // Returns: a / b -COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b) { - const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1; - si_int s_a = a >> bits_in_word_m1; // s_a = a < 0 ? -1 : 0 - si_int s_b = b >> bits_in_word_m1; // s_b = b < 0 ? -1 : 0 - a = (a ^ s_a) - s_a; // negate if s_a == -1 - b = (b ^ s_b) - s_b; // negate if s_b == -1 - s_a ^= s_b; // sign of quotient - // - // On CPUs without unsigned hardware division support, - // this calls __udivsi3 (notice the cast to su_int). - // On CPUs with unsigned hardware division support, - // this uses the unsigned division instruction. - // - return ((su_int)a / (su_int)b ^ s_a) - s_a; // negate if s_a == -1 -} +#define fixint_t si_int +#define fixuint_t su_int +// On CPUs without unsigned hardware division support, +// this calls __udivsi3 (notice the cast to su_int). +// On CPUs with unsigned hardware division support, +// this uses the unsigned division instruction. +#define COMPUTE_UDIV(a, b) ((su_int)(a) / (su_int)(b)) +#include "int_div_impl.inc" + +COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b) { return __divXi3(a, b); } #if defined(__ARM_EABI__) COMPILER_RT_ALIAS(__divsi3, __aeabi_idiv) diff --git a/system/lib/compiler-rt/lib/builtins/divtf3.c b/system/lib/compiler-rt/lib/builtins/divtf3.c index ce462d4d46c12..5bcc9a8e4aa18 100644 --- a/system/lib/compiler-rt/lib/builtins/divtf3.c +++ b/system/lib/compiler-rt/lib/builtins/divtf3.c @@ -9,213 +9,18 @@ // This file implements quad-precision soft-float division // with the IEEE-754 default rounding (to nearest, ties to even). // -// For simplicity, this implementation currently flushes denormals to zero. -// It should be a fairly straightforward exercise to implement gradual -// underflow with correct rounding. -// //===----------------------------------------------------------------------===// #define QUAD_PRECISION #include "fp_lib.h" #if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) -COMPILER_RT_ABI fp_t __divtf3(fp_t a, fp_t b) { - - const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; - const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; - const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit; - - rep_t aSignificand = toRep(a) & significandMask; - rep_t bSignificand = toRep(b) & significandMask; - int scale = 0; - - // Detect if a or b is zero, denormal, infinity, or NaN. - if (aExponent - 1U >= maxExponent - 1U || - bExponent - 1U >= maxExponent - 1U) { - - const rep_t aAbs = toRep(a) & absMask; - const rep_t bAbs = toRep(b) & absMask; - - // NaN / anything = qNaN - if (aAbs > infRep) - return fromRep(toRep(a) | quietBit); - // anything / NaN = qNaN - if (bAbs > infRep) - return fromRep(toRep(b) | quietBit); - - if (aAbs == infRep) { - // infinity / infinity = NaN - if (bAbs == infRep) - return fromRep(qnanRep); - // infinity / anything else = +/- infinity - else - return fromRep(aAbs | quotientSign); - } - - // anything else / infinity = +/- 0 - if (bAbs == infRep) - return fromRep(quotientSign); - - if (!aAbs) { - // zero / zero = NaN - if (!bAbs) - return fromRep(qnanRep); - // zero / anything else = +/- zero - else - return fromRep(quotientSign); - } - // anything else / zero = +/- infinity - if (!bAbs) - return fromRep(infRep | quotientSign); - - // One or both of a or b is denormal. The other (if applicable) is a - // normal number. Renormalize one or both of a and b, and set scale to - // include the necessary exponent adjustment. - if (aAbs < implicitBit) - scale += normalize(&aSignificand); - if (bAbs < implicitBit) - scale -= normalize(&bSignificand); - } - - // Set the implicit significand bit. If we fell through from the - // denormal path it was already set by normalize( ), but setting it twice - // won't hurt anything. - aSignificand |= implicitBit; - bSignificand |= implicitBit; - int quotientExponent = aExponent - bExponent + scale; - - // Align the significand of b as a Q63 fixed-point number in the range - // [1, 2.0) and get a Q64 approximate reciprocal using a small minimax - // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This - // is accurate to about 3.5 binary digits. - const uint64_t q63b = bSignificand >> 49; - uint64_t recip64 = UINT64_C(0x7504f333F9DE6484) - q63b; - // 0x7504f333F9DE6484 / 2^64 + 1 = 3/4 + 1/sqrt(2) - - // Now refine the reciprocal estimate using a Newton-Raphson iteration: - // - // x1 = x0 * (2 - x0 * b) - // - // This doubles the number of correct binary digits in the approximation - // with each iteration. - uint64_t correction64; - correction64 = -((rep_t)recip64 * q63b >> 64); - recip64 = (rep_t)recip64 * correction64 >> 63; - correction64 = -((rep_t)recip64 * q63b >> 64); - recip64 = (rep_t)recip64 * correction64 >> 63; - correction64 = -((rep_t)recip64 * q63b >> 64); - recip64 = (rep_t)recip64 * correction64 >> 63; - correction64 = -((rep_t)recip64 * q63b >> 64); - recip64 = (rep_t)recip64 * correction64 >> 63; - correction64 = -((rep_t)recip64 * q63b >> 64); - recip64 = (rep_t)recip64 * correction64 >> 63; - - // The reciprocal may have overflowed to zero if the upper half of b is - // exactly 1.0. This would sabatoge the full-width final stage of the - // computation that follows, so we adjust the reciprocal down by one bit. - recip64--; - - // We need to perform one more iteration to get us to 112 binary digits; - // The last iteration needs to happen with extra precision. - const uint64_t q127blo = bSignificand << 15; - rep_t correction, reciprocal; - - // NOTE: This operation is equivalent to __multi3, which is not implemented - // in some architechure - rep_t r64q63, r64q127, r64cH, r64cL, dummy; - wideMultiply((rep_t)recip64, (rep_t)q63b, &dummy, &r64q63); - wideMultiply((rep_t)recip64, (rep_t)q127blo, &dummy, &r64q127); - - correction = -(r64q63 + (r64q127 >> 64)); - - uint64_t cHi = correction >> 64; - uint64_t cLo = correction; - - wideMultiply((rep_t)recip64, (rep_t)cHi, &dummy, &r64cH); - wideMultiply((rep_t)recip64, (rep_t)cLo, &dummy, &r64cL); - - reciprocal = r64cH + (r64cL >> 64); - - // Adjust the final 128-bit reciprocal estimate downward to ensure that it - // is strictly smaller than the infinitely precise exact reciprocal. Because - // the computation of the Newton-Raphson step is truncating at every step, - // this adjustment is small; most of the work is already done. - reciprocal -= 2; - - // The numerical reciprocal is accurate to within 2^-112, lies in the - // interval [0.5, 1.0), and is strictly smaller than the true reciprocal - // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b - // in Q127 with the following properties: - // - // 1. q < a/b - // 2. q is in the interval [0.5, 2.0) - // 3. The error in q is bounded away from 2^-113 (actually, we have a - // couple of bits to spare, but this is all we need). - - // We need a 128 x 128 multiply high to compute q, which isn't a basic - // operation in C, so we need to be a little bit fussy. - rep_t quotient, quotientLo; - wideMultiply(aSignificand << 2, reciprocal, "ient, "ientLo); - - // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). - // In either case, we are going to compute a residual of the form - // - // r = a - q*b - // - // We know from the construction of q that r satisfies: - // - // 0 <= r < ulp(q)*b - // - // If r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we - // already have the correct result. The exact halfway case cannot occur. - // We also take this time to right shift quotient if it falls in the [1,2) - // range and adjust the exponent accordingly. - rep_t residual; - rep_t qb; - if (quotient < (implicitBit << 1)) { - wideMultiply(quotient, bSignificand, &dummy, &qb); - residual = (aSignificand << 113) - qb; - quotientExponent--; - } else { - quotient >>= 1; - wideMultiply(quotient, bSignificand, &dummy, &qb); - residual = (aSignificand << 112) - qb; - } +#define NUMBER_OF_HALF_ITERATIONS 4 +#define NUMBER_OF_FULL_ITERATIONS 1 - const int writtenExponent = quotientExponent + exponentBias; +#include "fp_div_impl.inc" - if (writtenExponent >= maxExponent) { - // If we have overflowed the exponent, return infinity. - return fromRep(infRep | quotientSign); - } else if (writtenExponent < 1) { - if (writtenExponent == 0) { - // Check whether the rounded result is normal. - const bool round = (residual << 1) > bSignificand; - // Clear the implicit bit. - rep_t absResult = quotient & significandMask; - // Round. - absResult += round; - if (absResult & ~significandMask) { - // The rounded result is normal; return it. - return fromRep(absResult | quotientSign); - } - } - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return fromRep(quotientSign); - } else { - const bool round = (residual << 1) >= bSignificand; - // Clear the implicit bit. - rep_t absResult = quotient & significandMask; - // Insert the exponent. - absResult |= (rep_t)writtenExponent << significandBits; - // Round. - absResult += round; - // Insert the sign and return. - const fp_t result = fromRep(absResult | quotientSign); - return result; - } -} +COMPILER_RT_ABI fp_t __divtf3(fp_t a, fp_t b) { return __divXf3__(a, b); } #endif diff --git a/system/lib/compiler-rt/lib/builtins/divti3.c b/system/lib/compiler-rt/lib/builtins/divti3.c index 6d007fe346546..80f2130b590e2 100644 --- a/system/lib/compiler-rt/lib/builtins/divti3.c +++ b/system/lib/compiler-rt/lib/builtins/divti3.c @@ -16,14 +16,11 @@ // Returns: a / b -COMPILER_RT_ABI ti_int __divti3(ti_int a, ti_int b) { - const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1; - ti_int s_a = a >> bits_in_tword_m1; // s_a = a < 0 ? -1 : 0 - ti_int s_b = b >> bits_in_tword_m1; // s_b = b < 0 ? -1 : 0 - a = (a ^ s_a) - s_a; // negate if s_a == -1 - b = (b ^ s_b) - s_b; // negate if s_b == -1 - s_a ^= s_b; // sign of quotient - return (__udivmodti4(a, b, (tu_int *)0) ^ s_a) - s_a; // negate if s_a == -1 -} +#define fixint_t ti_int +#define fixuint_t tu_int +#define COMPUTE_UDIV(a, b) __udivmodti4((a), (b), (tu_int *)0) +#include "int_div_impl.inc" + +COMPILER_RT_ABI ti_int __divti3(ti_int a, ti_int b) { return __divXi3(a, b); } #endif // CRT_HAS_128BIT diff --git a/system/lib/compiler-rt/lib/builtins/emutls.c b/system/lib/compiler-rt/lib/builtins/emutls.c index e0aa19155f7d3..98cabd917d6ce 100644 --- a/system/lib/compiler-rt/lib/builtins/emutls.c +++ b/system/lib/compiler-rt/lib/builtins/emutls.c @@ -182,9 +182,10 @@ static void emutls_exit(void) { } } -#pragma warning(push) -#pragma warning(disable : 4100) static BOOL CALLBACK emutls_init(PINIT_ONCE p0, PVOID p1, PVOID *p2) { + (void)p0; + (void)p1; + (void)p2; emutls_mutex = (LPCRITICAL_SECTION)_aligned_malloc(sizeof(CRITICAL_SECTION), 16); if (!emutls_mutex) { @@ -251,8 +252,6 @@ static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) { #endif // __ATOMIC_RELEASE -#pragma warning(pop) - #endif // _WIN32 static size_t emutls_num_object = 0; // number of allocated TLS objects diff --git a/system/lib/compiler-rt/lib/builtins/extendhfsf2.c b/system/lib/compiler-rt/lib/builtins/extendhfsf2.c index 7c1a76eb58517..0159ab09d3ebb 100644 --- a/system/lib/compiler-rt/lib/builtins/extendhfsf2.c +++ b/system/lib/compiler-rt/lib/builtins/extendhfsf2.c @@ -12,15 +12,15 @@ // Use a forwarding definition and noinline to implement a poor man's alias, // as there isn't a good cross-platform way of defining one. -COMPILER_RT_ABI NOINLINE float __extendhfsf2(uint16_t a) { +COMPILER_RT_ABI NOINLINE float __extendhfsf2(src_t a) { return __extendXfYf2__(a); } -COMPILER_RT_ABI float __gnu_h2f_ieee(uint16_t a) { return __extendhfsf2(a); } +COMPILER_RT_ABI float __gnu_h2f_ieee(src_t a) { return __extendhfsf2(a); } #if defined(__ARM_EABI__) #if defined(COMPILER_RT_ARMHF_TARGET) -AEABI_RTABI float __aeabi_h2f(uint16_t a) { return __extendhfsf2(a); } +AEABI_RTABI float __aeabi_h2f(src_t a) { return __extendhfsf2(a); } #else COMPILER_RT_ALIAS(__extendhfsf2, __aeabi_h2f) #endif diff --git a/system/lib/compiler-rt/lib/builtins/extendhftf2.c b/system/lib/compiler-rt/lib/builtins/extendhftf2.c new file mode 100644 index 0000000000000..aefe9737d34f9 --- /dev/null +++ b/system/lib/compiler-rt/lib/builtins/extendhftf2.c @@ -0,0 +1,23 @@ +//===-- lib/extendhftf2.c - half -> quad conversion ---------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define QUAD_PRECISION +#include "fp_lib.h" + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) && \ + defined(COMPILER_RT_HAS_FLOAT16) +#define SRC_HALF +#define DST_QUAD +#include "fp_extend_impl.inc" + +COMPILER_RT_ABI long double __extendhftf2(_Float16 a) { + return __extendXfYf2__(a); +} + +#endif diff --git a/system/lib/compiler-rt/lib/builtins/ffsdi2.c b/system/lib/compiler-rt/lib/builtins/ffsdi2.c index 9c1a242609567..beae5530430ed 100644 --- a/system/lib/compiler-rt/lib/builtins/ffsdi2.c +++ b/system/lib/compiler-rt/lib/builtins/ffsdi2.c @@ -15,13 +15,13 @@ // Returns: the index of the least significant 1-bit in a, or // the value zero if a is zero. The least significant bit is index one. -COMPILER_RT_ABI si_int __ffsdi2(di_int a) { +COMPILER_RT_ABI int __ffsdi2(di_int a) { dwords x; x.all = a; if (x.s.low == 0) { if (x.s.high == 0) return 0; - return __builtin_ctz(x.s.high) + (1 + sizeof(si_int) * CHAR_BIT); + return ctzsi(x.s.high) + (1 + sizeof(si_int) * CHAR_BIT); } - return __builtin_ctz(x.s.low) + 1; + return ctzsi(x.s.low) + 1; } diff --git a/system/lib/compiler-rt/lib/builtins/ffssi2.c b/system/lib/compiler-rt/lib/builtins/ffssi2.c index cba1f72fdc61a..ddb52927f8db9 100644 --- a/system/lib/compiler-rt/lib/builtins/ffssi2.c +++ b/system/lib/compiler-rt/lib/builtins/ffssi2.c @@ -15,9 +15,9 @@ // Returns: the index of the least significant 1-bit in a, or // the value zero if a is zero. The least significant bit is index one. -COMPILER_RT_ABI si_int __ffssi2(si_int a) { +COMPILER_RT_ABI int __ffssi2(si_int a) { if (a == 0) { return 0; } - return __builtin_ctz(a) + 1; + return ctzsi(a) + 1; } diff --git a/system/lib/compiler-rt/lib/builtins/ffsti2.c b/system/lib/compiler-rt/lib/builtins/ffsti2.c index a2d7ce08ada13..a2177d148a099 100644 --- a/system/lib/compiler-rt/lib/builtins/ffsti2.c +++ b/system/lib/compiler-rt/lib/builtins/ffsti2.c @@ -17,7 +17,7 @@ // Returns: the index of the least significant 1-bit in a, or // the value zero if a is zero. The least significant bit is index one. -COMPILER_RT_ABI si_int __ffsti2(ti_int a) { +COMPILER_RT_ABI int __ffsti2(ti_int a) { twords x; x.all = a; if (x.s.low == 0) { diff --git a/system/lib/compiler-rt/lib/builtins/floatdidf.c b/system/lib/compiler-rt/lib/builtins/floatdidf.c index 8f887314b9e1b..b2d8f2b44b6d3 100644 --- a/system/lib/compiler-rt/lib/builtins/floatdidf.c +++ b/system/lib/compiler-rt/lib/builtins/floatdidf.c @@ -87,7 +87,7 @@ COMPILER_RT_ABI double __floatdidf(di_int a) { } double_bits fb; fb.u.s.high = ((su_int)s & 0x80000000) | // sign - ((e + 1023) << 20) | // exponent + ((su_int)(e + 1023) << 20) | // exponent ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high fb.u.s.low = (su_int)a; // mantissa-low return fb.f; diff --git a/system/lib/compiler-rt/lib/builtins/floatdisf.c b/system/lib/compiler-rt/lib/builtins/floatdisf.c index cd9e0a3b78a50..faaa1bcb3c8ed 100644 --- a/system/lib/compiler-rt/lib/builtins/floatdisf.c +++ b/system/lib/compiler-rt/lib/builtins/floatdisf.c @@ -26,7 +26,7 @@ COMPILER_RT_ABI float __floatdisf(di_int a) { const di_int s = a >> (N - 1); a = (a ^ s) - s; int sd = N - __builtin_clzll(a); // number of significant digits - int e = sd - 1; // exponent + si_int e = sd - 1; // exponent if (sd > FLT_MANT_DIG) { // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR diff --git a/system/lib/compiler-rt/lib/builtins/floatsidf.c b/system/lib/compiler-rt/lib/builtins/floatsidf.c index 2c66167d794dc..28cf32f6388b5 100644 --- a/system/lib/compiler-rt/lib/builtins/floatsidf.c +++ b/system/lib/compiler-rt/lib/builtins/floatsidf.c @@ -17,7 +17,7 @@ #include "int_lib.h" -COMPILER_RT_ABI fp_t __floatsidf(int a) { +COMPILER_RT_ABI fp_t __floatsidf(si_int a) { const int aWidth = sizeof a * CHAR_BIT; @@ -33,14 +33,14 @@ COMPILER_RT_ABI fp_t __floatsidf(int a) { } // Exponent of (fp_t)a is the width of abs(a). - const int exponent = (aWidth - 1) - __builtin_clz(a); + const int exponent = (aWidth - 1) - clzsi(a); rep_t result; // Shift a into the significand field and clear the implicit bit. Extra // cast to unsigned int is necessary to get the correct behavior for // the input INT_MIN. const int shift = significandBits - exponent; - result = (rep_t)(unsigned int)a << shift ^ implicitBit; + result = (rep_t)(su_int)a << shift ^ implicitBit; // Insert the exponent result += (rep_t)(exponent + exponentBias) << significandBits; @@ -50,7 +50,7 @@ COMPILER_RT_ABI fp_t __floatsidf(int a) { #if defined(__ARM_EABI__) #if defined(COMPILER_RT_ARMHF_TARGET) -AEABI_RTABI fp_t __aeabi_i2d(int a) { return __floatsidf(a); } +AEABI_RTABI fp_t __aeabi_i2d(si_int a) { return __floatsidf(a); } #else COMPILER_RT_ALIAS(__floatsidf, __aeabi_i2d) #endif diff --git a/system/lib/compiler-rt/lib/builtins/floatundidf.c b/system/lib/compiler-rt/lib/builtins/floatundidf.c index e7c6aae5ce382..4c445b118080b 100644 --- a/system/lib/compiler-rt/lib/builtins/floatundidf.c +++ b/system/lib/compiler-rt/lib/builtins/floatundidf.c @@ -90,7 +90,7 @@ COMPILER_RT_ABI double __floatundidf(du_int a) { // a is now rounded to DBL_MANT_DIG bits } double_bits fb; - fb.u.s.high = ((e + 1023) << 20) | // exponent + fb.u.s.high = ((su_int)(e + 1023) << 20) | // exponent ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high fb.u.s.low = (su_int)a; // mantissa-low return fb.f; diff --git a/system/lib/compiler-rt/lib/builtins/floatundisf.c b/system/lib/compiler-rt/lib/builtins/floatundisf.c index 87841b761ded5..00d61b0c63107 100644 --- a/system/lib/compiler-rt/lib/builtins/floatundisf.c +++ b/system/lib/compiler-rt/lib/builtins/floatundisf.c @@ -24,7 +24,7 @@ COMPILER_RT_ABI float __floatundisf(du_int a) { return 0.0F; const unsigned N = sizeof(du_int) * CHAR_BIT; int sd = N - __builtin_clzll(a); // number of significant digits - int e = sd - 1; // 8 exponent + si_int e = sd - 1; // 8 exponent if (sd > FLT_MANT_DIG) { // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR diff --git a/system/lib/compiler-rt/lib/builtins/floatunsidf.c b/system/lib/compiler-rt/lib/builtins/floatunsidf.c index 2c01c3041434d..9b3e5fea0e45b 100644 --- a/system/lib/compiler-rt/lib/builtins/floatunsidf.c +++ b/system/lib/compiler-rt/lib/builtins/floatunsidf.c @@ -17,7 +17,7 @@ #include "int_lib.h" -COMPILER_RT_ABI fp_t __floatunsidf(unsigned int a) { +COMPILER_RT_ABI fp_t __floatunsidf(su_int a) { const int aWidth = sizeof a * CHAR_BIT; @@ -26,7 +26,7 @@ COMPILER_RT_ABI fp_t __floatunsidf(unsigned int a) { return fromRep(0); // Exponent of (fp_t)a is the width of abs(a). - const int exponent = (aWidth - 1) - __builtin_clz(a); + const int exponent = (aWidth - 1) - clzsi(a); rep_t result; // Shift a into the significand field and clear the implicit bit. @@ -40,7 +40,7 @@ COMPILER_RT_ABI fp_t __floatunsidf(unsigned int a) { #if defined(__ARM_EABI__) #if defined(COMPILER_RT_ARMHF_TARGET) -AEABI_RTABI fp_t __aeabi_ui2d(unsigned int a) { return __floatunsidf(a); } +AEABI_RTABI fp_t __aeabi_ui2d(su_int a) { return __floatunsidf(a); } #else COMPILER_RT_ALIAS(__floatunsidf, __aeabi_ui2d) #endif diff --git a/system/lib/compiler-rt/lib/builtins/fp_div_impl.inc b/system/lib/compiler-rt/lib/builtins/fp_div_impl.inc new file mode 100644 index 0000000000000..29bcd1920edfb --- /dev/null +++ b/system/lib/compiler-rt/lib/builtins/fp_div_impl.inc @@ -0,0 +1,419 @@ +//===-- fp_div_impl.inc - Floating point division -----------------*- C -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements soft-float division with the IEEE-754 default +// rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#include "fp_lib.h" + +// The __divXf3__ function implements Newton-Raphson floating point division. +// It uses 3 iterations for float32, 4 for float64 and 5 for float128, +// respectively. Due to number of significant bits being roughly doubled +// every iteration, the two modes are supported: N full-width iterations (as +// it is done for float32 by default) and (N-1) half-width iteration plus one +// final full-width iteration. It is expected that half-width integer +// operations (w.r.t rep_t size) can be performed faster for some hardware but +// they require error estimations to be computed separately due to larger +// computational errors caused by truncating intermediate results. + +// Half the bit-size of rep_t +#define HW (typeWidth / 2) +// rep_t-sized bitmask with lower half of bits set to ones +#define loMask (REP_C(-1) >> HW) + +#if NUMBER_OF_FULL_ITERATIONS < 1 +#error At least one full iteration is required +#endif + +static __inline fp_t __divXf3__(fp_t a, fp_t b) { + + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent - 1U >= maxExponent - 1U || + bExponent - 1U >= maxExponent - 1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN / anything = qNaN + if (aAbs > infRep) + return fromRep(toRep(a) | quietBit); + // anything / NaN = qNaN + if (bAbs > infRep) + return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity / infinity = NaN + if (bAbs == infRep) + return fromRep(qnanRep); + // infinity / anything else = +/- infinity + else + return fromRep(aAbs | quotientSign); + } + + // anything else / infinity = +/- 0 + if (bAbs == infRep) + return fromRep(quotientSign); + + if (!aAbs) { + // zero / zero = NaN + if (!bAbs) + return fromRep(qnanRep); + // zero / anything else = +/- zero + else + return fromRep(quotientSign); + } + // anything else / zero = +/- infinity + if (!bAbs) + return fromRep(infRep | quotientSign); + + // One or both of a or b is denormal. The other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) + scale += normalize(&aSignificand); + if (bAbs < implicitBit) + scale -= normalize(&bSignificand); + } + + // Set the implicit significand bit. If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything. + aSignificand |= implicitBit; + bSignificand |= implicitBit; + + int writtenExponent = (aExponent - bExponent + scale) + exponentBias; + + const rep_t b_UQ1 = bSignificand << (typeWidth - significandBits - 1); + + // Align the significand of b as a UQ1.(n-1) fixed-point number in the range + // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax + // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2. + // The max error for this approximation is achieved at endpoints, so + // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289..., + // which is about 4.5 bits. + // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571... + + // Then, refine the reciprocal estimate using a quadratically converging + // Newton-Raphson iteration: + // x_{n+1} = x_n * (2 - x_n * b) + // + // Let b be the original divisor considered "in infinite precision" and + // obtained from IEEE754 representation of function argument (with the + // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in + // UQ1.(W-1). + // + // Let b_hw be an infinitely precise number obtained from the highest (HW-1) + // bits of divisor significand (with the implicit bit set). Corresponds to + // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated** + // version of b_UQ1. + // + // Let e_n := x_n - 1/b_hw + // E_n := x_n - 1/b + // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b) + // = abs(e_n) + (b - b_hw) / (b*b_hw) + // <= abs(e_n) + 2 * 2^-HW + + // rep_t-sized iterations may be slower than the corresponding half-width + // variant depending on the handware and whether single/double/quad precision + // is selected. + // NB: Using half-width iterations increases computation errors due to + // rounding, so error estimations have to be computed taking the selected + // mode into account! +#if NUMBER_OF_HALF_ITERATIONS > 0 + // Starting with (n-1) half-width iterations + const half_rep_t b_UQ1_hw = bSignificand >> (significandBits + 1 - HW); + + // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW + // with W0 being either 16 or 32 and W0 <= HW. + // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which + // b/2 is subtracted to obtain x0) wrapped to [0, 1) range. +#if defined(SINGLE_PRECISION) + // Use 16-bit initial estimation in case we are using half-width iterations + // for float32 division. This is expected to be useful for some 16-bit + // targets. Not used by default as it requires performing more work during + // rounding and would hardly help on regular 32- or 64-bit targets. + const half_rep_t C_hw = HALF_REP_C(0x7504); +#else + // HW is at least 32. Shifting into the highest bits if needed. + const half_rep_t C_hw = HALF_REP_C(0x7504F333) << (HW - 32); +#endif + + // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572, + // so x0 fits to UQ0.HW without wrapping. + half_rep_t x_UQ0_hw = C_hw - (b_UQ1_hw /* exact b_hw/2 as UQ0.HW */); + // An e_0 error is comprised of errors due to + // * x0 being an inherently imprecise first approximation of 1/b_hw + // * C_hw being some (irrational) number **truncated** to W0 bits + // Please note that e_0 is calculated against the infinitely precise + // reciprocal of b_hw (that is, **truncated** version of b). + // + // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0 + + // By construction, 1 <= b < 2 + // f(x) = x * (2 - b*x) = 2*x - b*x^2 + // f'(x) = 2 * (1 - b*x) + // + // On the [0, 1] interval, f(0) = 0, + // then it increses until f(1/b) = 1 / b, maximum on (0, 1), + // then it decreses to f(1) = 2 - b + // + // Let g(x) = x - f(x) = b*x^2 - x. + // On (0, 1/b), g(x) < 0 <=> f(x) > x + // On (1/b, 1], g(x) > 0 <=> f(x) < x + // + // For half-width iterations, b_hw is used instead of b. + REPEAT_N_TIMES(NUMBER_OF_HALF_ITERATIONS, { + // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp + // of corr_UQ1_hw. + // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1). + // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided + // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is + // expected to be strictly positive because b_UQ1_hw has its highest bit set + // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1). + half_rep_t corr_UQ1_hw = 0 - ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW); + + // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally + // obtaining an UQ1.(HW-1) number and proving its highest bit could be + // considered to be 0 to be able to represent it in UQ0.HW. + // From the above analysis of f(x), if corr_UQ1_hw would be represented + // without any intermediate loss of precision (that is, in twice_rep_t) + // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly + // less otherwise. On the other hand, to obtain [1.]000..., one have to pass + // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due + // to 1.0 being not representable as UQ0.HW). + // The fact corr_UQ1_hw was virtually round up (due to result of + // multiplication being **first** truncated, then negated - to improve + // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw. + x_UQ0_hw = (rep_t)x_UQ0_hw * corr_UQ1_hw >> (HW - 1); + // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t + // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after + // any number of iterations, so just subtract 2 from the reciprocal + // approximation after last iteration. + + // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW: + // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1 + // = 1 - e_n * b_hw + 2*eps1 + // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2 + // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2 + // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2 + // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw + // \------ >0 -------/ \-- >0 ---/ + // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U) + }) + // For initial half-width iterations, U = 2^-HW + // Let abs(e_n) <= u_n * U, + // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U) + // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2) + + // Account for possible overflow (see above). For an overflow to occur for the + // first time, for "ideal" corr_UQ1_hw (that is, without intermediate + // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum + // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to + // be not below that value (see g(x) above), so it is safe to decrement just + // once after the final iteration. On the other hand, an effective value of + // divisor changes after this point (from b_hw to b), so adjust here. + x_UQ0_hw -= 1U; + rep_t x_UQ0 = (rep_t)x_UQ0_hw << HW; + x_UQ0 -= 1U; + +#else + // C is (3/4 + 1/sqrt(2)) - 1 truncated to 32 fractional bits as UQ0.n + const rep_t C = REP_C(0x7504F333) << (typeWidth - 32); + rep_t x_UQ0 = C - b_UQ1; + // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-32 +#endif + + // Error estimations for full-precision iterations are calculated just + // as above, but with U := 2^-W and taking extra decrementing into account. + // We need at least one such iteration. + +#ifdef USE_NATIVE_FULL_ITERATIONS + REPEAT_N_TIMES(NUMBER_OF_FULL_ITERATIONS, { + rep_t corr_UQ1 = 0 - ((twice_rep_t)x_UQ0 * b_UQ1 >> typeWidth); + x_UQ0 = (twice_rep_t)x_UQ0 * corr_UQ1 >> (typeWidth - 1); + }) +#else +#if NUMBER_OF_FULL_ITERATIONS != 1 +#error Only a single emulated full iteration is supported +#endif +#if !(NUMBER_OF_HALF_ITERATIONS > 0) + // Cannot normally reach here: only one full-width iteration is requested and + // the total number of iterations should be at least 3 even for float32. +#error Check NUMBER_OF_HALF_ITERATIONS, NUMBER_OF_FULL_ITERATIONS and USE_NATIVE_FULL_ITERATIONS. +#endif + // Simulating operations on a twice_rep_t to perform a single final full-width + // iteration. Using ad-hoc multiplication implementations to take advantage + // of particular structure of operands. + rep_t blo = b_UQ1 & loMask; + // x_UQ0 = x_UQ0_hw * 2^HW - 1 + // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1 + // + // <--- higher half ---><--- lower half ---> + // [x_UQ0_hw * b_UQ1_hw] + // + [ x_UQ0_hw * blo ] + // - [ b_UQ1 ] + // = [ result ][.... discarded ...] + rep_t corr_UQ1 = 0U - ( (rep_t)x_UQ0_hw * b_UQ1_hw + + ((rep_t)x_UQ0_hw * blo >> HW) + - REP_C(1)); // account for *possible* carry + rep_t lo_corr = corr_UQ1 & loMask; + rep_t hi_corr = corr_UQ1 >> HW; + // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1 + x_UQ0 = ((rep_t)x_UQ0_hw * hi_corr << 1) + + ((rep_t)x_UQ0_hw * lo_corr >> (HW - 1)) + - REP_C(2); // 1 to account for the highest bit of corr_UQ1 can be 1 + // 1 to account for possible carry + // Just like the case of half-width iterations but with possibility + // of overflowing by one extra Ulp of x_UQ0. + x_UQ0 -= 1U; + // ... and then traditional fixup by 2 should work + + // On error estimation: + // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW + // + (2^-HW + 2^-W)) + // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW + + // Then like for the half-width iterations: + // With 0 <= eps1, eps2 < 2^-W + // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b + // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ] + // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ] +#endif + + // Finally, account for possible overflow, as explained above. + x_UQ0 -= 2U; + + // u_n for different precisions (with N-1 half-width iterations): + // W0 is the precision of C + // u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW + + // Estimated with bc: + // define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; } + // define half2(un) { return 2.0 * un / 2.0^hw + 2.0; } + // define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; } + // define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; } + + // | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1) + // u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797 + // u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440 + // u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317 + // u_3 | < 7.31 | | < 7.31 | < 27054456580 + // u_4 | | | | < 80.4 + // Final (U_N) | same as u_3 | < 72 | < 218 | < 13920 + + // Add 2 to U_N due to final decrement. + +#if defined(SINGLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 2 && NUMBER_OF_FULL_ITERATIONS == 1 +#define RECIPROCAL_PRECISION REP_C(74) +#elif defined(SINGLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 0 && NUMBER_OF_FULL_ITERATIONS == 3 +#define RECIPROCAL_PRECISION REP_C(10) +#elif defined(DOUBLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 3 && NUMBER_OF_FULL_ITERATIONS == 1 +#define RECIPROCAL_PRECISION REP_C(220) +#elif defined(QUAD_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 4 && NUMBER_OF_FULL_ITERATIONS == 1 +#define RECIPROCAL_PRECISION REP_C(13922) +#else +#error Invalid number of iterations +#endif + + // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W + x_UQ0 -= RECIPROCAL_PRECISION; + // Now 1/b - (2*P) * 2^-W < x < 1/b + // FIXME Is x_UQ0 still >= 0.5? + + rep_t quotient_UQ1, dummy; + wideMultiply(x_UQ0, aSignificand << 1, "ient_UQ1, &dummy); + // Now, a/b - 4*P * 2^-W < q < a/b for q= in UQ1.(SB+1+W). + + // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1), + // adjust it to be in [1.0, 2.0) as UQ1.SB. + rep_t residualLo; + if (quotient_UQ1 < (implicitBit << 1)) { + // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, + // effectively doubling its value as well as its error estimation. + residualLo = (aSignificand << (significandBits + 1)) - quotient_UQ1 * bSignificand; + writtenExponent -= 1; + aSignificand <<= 1; + } else { + // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it + // to UQ1.SB by right shifting by 1. Least significant bit is omitted. + quotient_UQ1 >>= 1; + residualLo = (aSignificand << significandBits) - quotient_UQ1 * bSignificand; + } + // NB: residualLo is calculated above for the normal result case. + // It is re-computed on denormal path that is expected to be not so + // performance-sensitive. + + // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB + // Each NextAfter() increments the floating point value by at least 2^-SB + // (more, if exponent was incremented). + // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint): + // q + // | | * | | | | | + // <---> 2^t + // | | | | | * | | + // q + // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB. + // (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB + // (8*P) * 2^-W < 0.5 * 2^-SB + // P < 2^(W-4-SB) + // Generally, for at most R NextAfter() to be enough, + // P < (2*R - 1) * 2^(W-4-SB) + // For f32 (0+3): 10 < 32 (OK) + // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required + // For f64: 220 < 256 (OK) + // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required) + + // If we have overflowed the exponent, return infinity + if (writtenExponent >= maxExponent) + return fromRep(infRep | quotientSign); + + // Now, quotient_UQ1_SB <= the correctly-rounded result + // and may need taking NextAfter() up to 3 times (see error estimates above) + // r = a - b * q + rep_t absResult; + if (writtenExponent > 0) { + // Clear the implicit bit + absResult = quotient_UQ1 & significandMask; + // Insert the exponent + absResult |= (rep_t)writtenExponent << significandBits; + residualLo <<= 1; + } else { + // Prevent shift amount from being negative + if (significandBits + writtenExponent < 0) + return fromRep(quotientSign); + + absResult = quotient_UQ1 >> (-writtenExponent + 1); + + // multiplied by two to prevent shift amount to be negative + residualLo = (aSignificand << (significandBits + writtenExponent)) - (absResult * bSignificand << 1); + } + + // Round + residualLo += absResult & 1; // tie to even + // The above line conditionally turns the below LT comparison into LTE + absResult += residualLo > bSignificand; +#if defined(QUAD_PRECISION) || (defined(SINGLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS > 0) + // Do not round Infinity to NaN + absResult += absResult < infRep && residualLo > (2 + 1) * bSignificand; +#endif +#if defined(QUAD_PRECISION) + absResult += absResult < infRep && residualLo > (4 + 1) * bSignificand; +#endif + return fromRep(absResult | quotientSign); +} diff --git a/system/lib/compiler-rt/lib/builtins/fp_extend.h b/system/lib/compiler-rt/lib/builtins/fp_extend.h index d2083c4267225..aad4436730dd4 100644 --- a/system/lib/compiler-rt/lib/builtins/fp_extend.h +++ b/system/lib/compiler-rt/lib/builtins/fp_extend.h @@ -21,7 +21,7 @@ typedef float src_t; typedef uint32_t src_rep_t; #define SRC_REP_C UINT32_C static const int srcSigBits = 23; -#define src_rep_t_clz __builtin_clz +#define src_rep_t_clz clzsi #elif defined SRC_DOUBLE typedef double src_t; @@ -40,7 +40,11 @@ static __inline int src_rep_t_clz(src_rep_t a) { } #elif defined SRC_HALF +#ifdef COMPILER_RT_HAS_FLOAT16 +typedef _Float16 src_t; +#else typedef uint16_t src_t; +#endif typedef uint16_t src_rep_t; #define SRC_REP_C UINT16_C static const int srcSigBits = 10; diff --git a/system/lib/compiler-rt/lib/builtins/fp_lib.h b/system/lib/compiler-rt/lib/builtins/fp_lib.h index e2a906681c46d..f22feafa4e694 100644 --- a/system/lib/compiler-rt/lib/builtins/fp_lib.h +++ b/system/lib/compiler-rt/lib/builtins/fp_lib.h @@ -40,13 +40,16 @@ #if defined SINGLE_PRECISION +typedef uint16_t half_rep_t; typedef uint32_t rep_t; +typedef uint64_t twice_rep_t; typedef int32_t srep_t; typedef float fp_t; +#define HALF_REP_C UINT16_C #define REP_C UINT32_C #define significandBits 23 -static __inline int rep_clz(rep_t a) { return __builtin_clz(a); } +static __inline int rep_clz(rep_t a) { return clzsi(a); } // 32x32 --> 64 bit multiply static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) { @@ -58,9 +61,11 @@ COMPILER_RT_ABI fp_t __addsf3(fp_t a, fp_t b); #elif defined DOUBLE_PRECISION +typedef uint32_t half_rep_t; typedef uint64_t rep_t; typedef int64_t srep_t; typedef double fp_t; +#define HALF_REP_C UINT32_C #define REP_C UINT64_C #define significandBits 52 @@ -69,9 +74,9 @@ static __inline int rep_clz(rep_t a) { return __builtin_clzl(a); #else if (a & REP_C(0xffffffff00000000)) - return __builtin_clz(a >> 32); + return clzsi(a >> 32); else - return 32 + __builtin_clz(a & REP_C(0xffffffff)); + return 32 + clzsi(a & REP_C(0xffffffff)); #endif } @@ -102,9 +107,11 @@ COMPILER_RT_ABI fp_t __adddf3(fp_t a, fp_t b); #elif defined QUAD_PRECISION #if __LDBL_MANT_DIG__ == 113 && defined(__SIZEOF_INT128__) #define CRT_LDBL_128BIT +typedef uint64_t half_rep_t; typedef __uint128_t rep_t; typedef __int128_t srep_t; typedef long double fp_t; +#define HALF_REP_C UINT64_C #define REP_C (__uint128_t) // Note: Since there is no explicit way to tell compiler the constant is a // 128-bit integer, we let the constant be casted to 128-bit integer diff --git a/system/lib/compiler-rt/lib/builtins/fp_mode.h b/system/lib/compiler-rt/lib/builtins/fp_mode.h index 51bec0431a402..4ba682c384f2d 100644 --- a/system/lib/compiler-rt/lib/builtins/fp_mode.h +++ b/system/lib/compiler-rt/lib/builtins/fp_mode.h @@ -23,7 +23,7 @@ typedef enum { FE_TOWARDZERO } FE_ROUND_MODE; -FE_ROUND_MODE __fe_getround(); -int __fe_raise_inexact(); +FE_ROUND_MODE __fe_getround(void); +int __fe_raise_inexact(void); #endif // FP_MODE_H diff --git a/system/lib/compiler-rt/lib/builtins/fp_trunc.h b/system/lib/compiler-rt/lib/builtins/fp_trunc.h index aca4c9b6e6777..00595edd5e018 100644 --- a/system/lib/compiler-rt/lib/builtins/fp_trunc.h +++ b/system/lib/compiler-rt/lib/builtins/fp_trunc.h @@ -50,7 +50,11 @@ typedef uint32_t dst_rep_t; static const int dstSigBits = 23; #elif defined DST_HALF +#ifdef COMPILER_RT_HAS_FLOAT16 +typedef _Float16 dst_t; +#else typedef uint16_t dst_t; +#endif typedef uint16_t dst_rep_t; #define DST_REP_C UINT16_C static const int dstSigBits = 10; diff --git a/system/lib/compiler-rt/lib/builtins/int_div_impl.inc b/system/lib/compiler-rt/lib/builtins/int_div_impl.inc new file mode 100644 index 0000000000000..dc1f97cbeae53 --- /dev/null +++ b/system/lib/compiler-rt/lib/builtins/int_div_impl.inc @@ -0,0 +1,95 @@ +//===-- int_div_impl.inc - Integer division ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Helpers used by __udivsi3, __umodsi3, __udivdi3, and __umodsi3. +// +//===----------------------------------------------------------------------===// + +#define clz(a) (sizeof(a) == sizeof(unsigned long long) ? __builtin_clzll(a) : clzsi(a)) + +// Adapted from Figure 3-40 of The PowerPC Compiler Writer's Guide +static __inline fixuint_t __udivXi3(fixuint_t n, fixuint_t d) { + const unsigned N = sizeof(fixuint_t) * CHAR_BIT; + // d == 0 cases are unspecified. + unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N); + // 0 <= sr <= N - 1 or sr is very large. + if (sr > N - 1) // n < d + return 0; + if (sr == N - 1) // d == 1 + return n; + ++sr; + // 1 <= sr <= N - 1. Shifts do not trigger UB. + fixuint_t r = n >> sr; + n <<= N - sr; + fixuint_t carry = 0; + for (; sr > 0; --sr) { + r = (r << 1) | (n >> (N - 1)); + n = (n << 1) | carry; + // Branch-less version of: + // carry = 0; + // if (r >= d) r -= d, carry = 1; + const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1); + carry = s & 1; + r -= d & s; + } + n = (n << 1) | carry; + return n; +} + +// Mostly identical to __udivXi3 but the return values are different. +static __inline fixuint_t __umodXi3(fixuint_t n, fixuint_t d) { + const unsigned N = sizeof(fixuint_t) * CHAR_BIT; + // d == 0 cases are unspecified. + unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N); + // 0 <= sr <= N - 1 or sr is very large. + if (sr > N - 1) // n < d + return n; + if (sr == N - 1) // d == 1 + return 0; + ++sr; + // 1 <= sr <= N - 1. Shifts do not trigger UB. + fixuint_t r = n >> sr; + n <<= N - sr; + fixuint_t carry = 0; + for (; sr > 0; --sr) { + r = (r << 1) | (n >> (N - 1)); + n = (n << 1) | carry; + // Branch-less version of: + // carry = 0; + // if (r >= d) r -= d, carry = 1; + const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1); + carry = s & 1; + r -= d & s; + } + return r; +} + +#ifdef COMPUTE_UDIV +static __inline fixint_t __divXi3(fixint_t a, fixint_t b) { + const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1; + fixint_t s_a = a >> N; // s_a = a < 0 ? -1 : 0 + fixint_t s_b = b >> N; // s_b = b < 0 ? -1 : 0 + fixuint_t a_u = (fixuint_t)(a ^ s_a) + (-s_a); // negate if s_a == -1 + fixuint_t b_u = (fixuint_t)(b ^ s_b) + (-s_b); // negate if s_b == -1 + s_a ^= s_b; // sign of quotient + return (COMPUTE_UDIV(a_u, b_u) ^ s_a) + (-s_a); // negate if s_a == -1 +} +#endif // COMPUTE_UDIV + +#ifdef ASSIGN_UMOD +static __inline fixint_t __modXi3(fixint_t a, fixint_t b) { + const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1; + fixint_t s = b >> N; // s = b < 0 ? -1 : 0 + fixuint_t b_u = (fixuint_t)(b ^ s) + (-s); // negate if s == -1 + s = a >> N; // s = a < 0 ? -1 : 0 + fixuint_t a_u = (fixuint_t)(a ^ s) + (-s); // negate if s == -1 + fixuint_t res; + ASSIGN_UMOD(res, a_u, b_u); + return (res ^ s) + (-s); // negate if s == -1 +} +#endif // ASSIGN_UMOD diff --git a/system/lib/compiler-rt/lib/builtins/int_lib.h b/system/lib/compiler-rt/lib/builtins/int_lib.h index 3092f68c084a6..991c4a99ea6e2 100644 --- a/system/lib/compiler-rt/lib/builtins/int_lib.h +++ b/system/lib/compiler-rt/lib/builtins/int_lib.h @@ -48,12 +48,20 @@ #define XSTR(a) STR(a) #define SYMBOL_NAME(name) XSTR(__USER_LABEL_PREFIX__) #name -#if defined(__ELF__) || defined(__MINGW32__) || defined(__wasm__) +#if defined(__ELF__) || defined(__MINGW32__) || defined(__wasm__) || \ + defined(_AIX) #define COMPILER_RT_ALIAS(name, aliasname) \ COMPILER_RT_ABI __typeof(name) aliasname __attribute__((__alias__(#name))); #elif defined(__APPLE__) +#if defined(VISIBILITY_HIDDEN) +#define COMPILER_RT_ALIAS_VISIBILITY(name) \ + __asm__(".private_extern " SYMBOL_NAME(name)); +#else +#define COMPILER_RT_ALIAS_VISIBILITY(name) +#endif #define COMPILER_RT_ALIAS(name, aliasname) \ __asm__(".globl " SYMBOL_NAME(aliasname)); \ + COMPILER_RT_ALIAS_VISIBILITY(aliasname) \ __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \ COMPILER_RT_ABI __typeof(name) aliasname; #elif defined(_WIN32) @@ -84,8 +92,8 @@ // Include internal utility function declarations. #include "int_util.h" -COMPILER_RT_ABI si_int __paritysi2(si_int a); -COMPILER_RT_ABI si_int __paritydi2(di_int a); +COMPILER_RT_ABI int __paritysi2(si_int a); +COMPILER_RT_ABI int __paritydi2(di_int a); COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b); COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b); @@ -94,7 +102,7 @@ COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d); COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int *rem); COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem); #ifdef CRT_HAS_128BIT -COMPILER_RT_ABI si_int __clzti2(ti_int a); +COMPILER_RT_ABI int __clzti2(ti_int a); COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem); #endif @@ -102,14 +110,14 @@ COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem); #if defined(_MSC_VER) && !defined(__clang__) #include -uint32_t __inline __builtin_ctz(uint32_t value) { +int __inline __builtin_ctz(uint32_t value) { unsigned long trailing_zero = 0; if (_BitScanForward(&trailing_zero, value)) return trailing_zero; return 32; } -uint32_t __inline __builtin_clz(uint32_t value) { +int __inline __builtin_clz(uint32_t value) { unsigned long leading_zero = 0; if (_BitScanReverse(&leading_zero, value)) return 31 - leading_zero; @@ -117,14 +125,14 @@ uint32_t __inline __builtin_clz(uint32_t value) { } #if defined(_M_ARM) || defined(_M_X64) -uint32_t __inline __builtin_clzll(uint64_t value) { +int __inline __builtin_clzll(uint64_t value) { unsigned long leading_zero = 0; if (_BitScanReverse64(&leading_zero, value)) return 63 - leading_zero; return 64; } #else -uint32_t __inline __builtin_clzll(uint64_t value) { +int __inline __builtin_clzll(uint64_t value) { if (value == 0) return 64; uint32_t msh = (uint32_t)(value >> 32); diff --git a/system/lib/compiler-rt/lib/builtins/int_mulo_impl.inc b/system/lib/compiler-rt/lib/builtins/int_mulo_impl.inc new file mode 100644 index 0000000000000..567d8b9e6e603 --- /dev/null +++ b/system/lib/compiler-rt/lib/builtins/int_mulo_impl.inc @@ -0,0 +1,49 @@ +//===-- int_mulo_impl.inc - Implement __mulo[sdt]i4 ---------------*- C -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Helper used by __mulosi4, __mulodi4 and __muloti4. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Returns: a * b + +// Effects: sets *overflow to 1 if a * b overflows + +static __inline fixint_t __muloXi4(fixint_t a, fixint_t b, int *overflow) { + const int N = (int)(sizeof(fixint_t) * CHAR_BIT); + const fixint_t MIN = (fixint_t)1 << (N - 1); + const fixint_t MAX = ~MIN; + *overflow = 0; + fixint_t result = a * b; + if (a == MIN) { + if (b != 0 && b != 1) + *overflow = 1; + return result; + } + if (b == MIN) { + if (a != 0 && a != 1) + *overflow = 1; + return result; + } + fixint_t sa = a >> (N - 1); + fixint_t abs_a = (a ^ sa) - sa; + fixint_t sb = b >> (N - 1); + fixint_t abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return result; + if (sa == sb) { + if (abs_a > MAX / abs_b) + *overflow = 1; + } else { + if (abs_a > MIN / -abs_b) + *overflow = 1; + } + return result; +} diff --git a/system/lib/compiler-rt/lib/builtins/int_mulv_impl.inc b/system/lib/compiler-rt/lib/builtins/int_mulv_impl.inc new file mode 100644 index 0000000000000..1e920716ec499 --- /dev/null +++ b/system/lib/compiler-rt/lib/builtins/int_mulv_impl.inc @@ -0,0 +1,47 @@ +//===-- int_mulv_impl.inc - Implement __mulv[sdt]i3 ---------------*- C -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Helper used by __mulvsi3, __mulvdi3 and __mulvti3. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Returns: a * b + +// Effects: aborts if a * b overflows + +static __inline fixint_t __mulvXi3(fixint_t a, fixint_t b) { + const int N = (int)(sizeof(fixint_t) * CHAR_BIT); + const fixint_t MIN = (fixint_t)1 << (N - 1); + const fixint_t MAX = ~MIN; + if (a == MIN) { + if (b == 0 || b == 1) + return a * b; + compilerrt_abort(); + } + if (b == MIN) { + if (a == 0 || a == 1) + return a * b; + compilerrt_abort(); + } + fixint_t sa = a >> (N - 1); + fixint_t abs_a = (a ^ sa) - sa; + fixint_t sb = b >> (N - 1); + fixint_t abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return a * b; + if (sa == sb) { + if (abs_a > MAX / abs_b) + compilerrt_abort(); + } else { + if (abs_a > MIN / -abs_b) + compilerrt_abort(); + } + return a * b; +} diff --git a/system/lib/compiler-rt/lib/builtins/int_types.h b/system/lib/compiler-rt/lib/builtins/int_types.h index f89220d543509..705355a4840d4 100644 --- a/system/lib/compiler-rt/lib/builtins/int_types.h +++ b/system/lib/compiler-rt/lib/builtins/int_types.h @@ -22,11 +22,20 @@ #ifdef si_int #undef si_int #endif -typedef int si_int; -typedef unsigned su_int; +typedef int32_t si_int; +typedef uint32_t su_int; +#if UINT_MAX == 0xFFFFFFFF +#define clzsi __builtin_clz +#define ctzsi __builtin_ctz +#elif ULONG_MAX == 0xFFFFFFFF +#define clzsi __builtin_clzl +#define ctzsi __builtin_ctzl +#else +#error could not determine appropriate clzsi macro for this system +#endif -typedef long long di_int; -typedef unsigned long long du_int; +typedef int64_t di_int; +typedef uint64_t du_int; typedef union { di_int all; @@ -135,9 +144,12 @@ typedef struct { // Check if the target supports 80 bit extended precision long doubles. // Notably, on x86 Windows, MSVC only provides a 64-bit long double, but GCC // still makes it 80 bits. Clang will match whatever compiler it is trying to -// be compatible with. -#if ((defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)) || \ - defined(__m68k__) || defined(__ia64__) +// be compatible with. On 32-bit x86 Android, long double is 64 bits, while on +// x86_64 Android, long double is 128 bits. +#if (defined(__i386__) || defined(__x86_64__)) && \ + !(defined(_MSC_VER) || defined(__ANDROID__)) +#define HAS_80_BIT_LONG_DOUBLE 1 +#elif defined(__m68k__) || defined(__ia64__) #define HAS_80_BIT_LONG_DOUBLE 1 #else #define HAS_80_BIT_LONG_DOUBLE 0 diff --git a/system/lib/compiler-rt/lib/builtins/int_util.h b/system/lib/compiler-rt/lib/builtins/int_util.h index 5fbdfb57c1e74..c372c2edc6371 100644 --- a/system/lib/compiler-rt/lib/builtins/int_util.h +++ b/system/lib/compiler-rt/lib/builtins/int_util.h @@ -28,4 +28,20 @@ NORETURN void __compilerrt_abort_impl(const char *file, int line, #define COMPILE_TIME_ASSERT2(expr, cnt) \ typedef char ct_assert_##cnt[(expr) ? 1 : -1] UNUSED +// Force unrolling the code specified to be repeated N times. +#define REPEAT_0_TIMES(code_to_repeat) /* do nothing */ +#define REPEAT_1_TIMES(code_to_repeat) code_to_repeat +#define REPEAT_2_TIMES(code_to_repeat) \ + REPEAT_1_TIMES(code_to_repeat) \ + code_to_repeat +#define REPEAT_3_TIMES(code_to_repeat) \ + REPEAT_2_TIMES(code_to_repeat) \ + code_to_repeat +#define REPEAT_4_TIMES(code_to_repeat) \ + REPEAT_3_TIMES(code_to_repeat) \ + code_to_repeat + +#define REPEAT_N_TIMES_(N, code_to_repeat) REPEAT_##N##_TIMES(code_to_repeat) +#define REPEAT_N_TIMES(N, code_to_repeat) REPEAT_N_TIMES_(N, code_to_repeat) + #endif // INT_UTIL_H diff --git a/system/lib/compiler-rt/lib/builtins/lshrdi3.c b/system/lib/compiler-rt/lib/builtins/lshrdi3.c index 97e08e1e9ba0b..6072152583ac5 100644 --- a/system/lib/compiler-rt/lib/builtins/lshrdi3.c +++ b/system/lib/compiler-rt/lib/builtins/lshrdi3.c @@ -16,7 +16,7 @@ // Precondition: 0 <= b < bits_in_dword -COMPILER_RT_ABI di_int __lshrdi3(di_int a, si_int b) { +COMPILER_RT_ABI di_int __lshrdi3(di_int a, int b) { const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT); udwords input; udwords result; diff --git a/system/lib/compiler-rt/lib/builtins/moddi3.c b/system/lib/compiler-rt/lib/builtins/moddi3.c index 92b0996077c64..15cf80b995557 100644 --- a/system/lib/compiler-rt/lib/builtins/moddi3.c +++ b/system/lib/compiler-rt/lib/builtins/moddi3.c @@ -14,13 +14,9 @@ // Returns: a % b -COMPILER_RT_ABI di_int __moddi3(di_int a, di_int b) { - const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; - di_int s = b >> bits_in_dword_m1; // s = b < 0 ? -1 : 0 - b = (b ^ s) - s; // negate if s == -1 - s = a >> bits_in_dword_m1; // s = a < 0 ? -1 : 0 - a = (a ^ s) - s; // negate if s == -1 - du_int r; - __udivmoddi4(a, b, &r); - return ((di_int)r ^ s) - s; // negate if s == -1 -} +#define fixint_t di_int +#define fixuint_t du_int +#define ASSIGN_UMOD(res, a, b) __udivmoddi4((a), (b), &(res)) +#include "int_div_impl.inc" + +COMPILER_RT_ABI di_int __moddi3(di_int a, di_int b) { return __modXi3(a, b); } diff --git a/system/lib/compiler-rt/lib/builtins/modti3.c b/system/lib/compiler-rt/lib/builtins/modti3.c index d11fe220b7691..7c10cfd39027b 100644 --- a/system/lib/compiler-rt/lib/builtins/modti3.c +++ b/system/lib/compiler-rt/lib/builtins/modti3.c @@ -16,15 +16,11 @@ // Returns: a % b -COMPILER_RT_ABI ti_int __modti3(ti_int a, ti_int b) { - const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1; - ti_int s = b >> bits_in_tword_m1; // s = b < 0 ? -1 : 0 - b = (b ^ s) - s; // negate if s == -1 - s = a >> bits_in_tword_m1; // s = a < 0 ? -1 : 0 - a = (a ^ s) - s; // negate if s == -1 - tu_int r; - __udivmodti4(a, b, &r); - return ((ti_int)r ^ s) - s; // negate if s == -1 -} +#define fixint_t ti_int +#define fixuint_t tu_int +#define ASSIGN_UMOD(res, a, b) __udivmodti4((a), (b), &(res)) +#include "int_div_impl.inc" + +COMPILER_RT_ABI ti_int __modti3(ti_int a, ti_int b) { return __modXi3(a, b); } #endif // CRT_HAS_128BIT diff --git a/system/lib/compiler-rt/lib/builtins/mulodi4.c b/system/lib/compiler-rt/lib/builtins/mulodi4.c index 23f5571ac4689..7209676a327e4 100644 --- a/system/lib/compiler-rt/lib/builtins/mulodi4.c +++ b/system/lib/compiler-rt/lib/builtins/mulodi4.c @@ -10,40 +10,13 @@ // //===----------------------------------------------------------------------===// -#include "int_lib.h" +#define fixint_t di_int +#include "int_mulo_impl.inc" // Returns: a * b // Effects: sets *overflow to 1 if a * b overflows COMPILER_RT_ABI di_int __mulodi4(di_int a, di_int b, int *overflow) { - const int N = (int)(sizeof(di_int) * CHAR_BIT); - const di_int MIN = (di_int)1 << (N - 1); - const di_int MAX = ~MIN; - *overflow = 0; - di_int result = a * b; - if (a == MIN) { - if (b != 0 && b != 1) - *overflow = 1; - return result; - } - if (b == MIN) { - if (a != 0 && a != 1) - *overflow = 1; - return result; - } - di_int sa = a >> (N - 1); - di_int abs_a = (a ^ sa) - sa; - di_int sb = b >> (N - 1); - di_int abs_b = (b ^ sb) - sb; - if (abs_a < 2 || abs_b < 2) - return result; - if (sa == sb) { - if (abs_a > MAX / abs_b) - *overflow = 1; - } else { - if (abs_a > MIN / -abs_b) - *overflow = 1; - } - return result; + return __muloXi4(a, b, overflow); } diff --git a/system/lib/compiler-rt/lib/builtins/mulosi4.c b/system/lib/compiler-rt/lib/builtins/mulosi4.c index fea4311296f8b..4e03c24455d67 100644 --- a/system/lib/compiler-rt/lib/builtins/mulosi4.c +++ b/system/lib/compiler-rt/lib/builtins/mulosi4.c @@ -10,40 +10,13 @@ // //===----------------------------------------------------------------------===// -#include "int_lib.h" +#define fixint_t si_int +#include "int_mulo_impl.inc" // Returns: a * b // Effects: sets *overflow to 1 if a * b overflows COMPILER_RT_ABI si_int __mulosi4(si_int a, si_int b, int *overflow) { - const int N = (int)(sizeof(si_int) * CHAR_BIT); - const si_int MIN = (si_int)1 << (N - 1); - const si_int MAX = ~MIN; - *overflow = 0; - si_int result = a * b; - if (a == MIN) { - if (b != 0 && b != 1) - *overflow = 1; - return result; - } - if (b == MIN) { - if (a != 0 && a != 1) - *overflow = 1; - return result; - } - si_int sa = a >> (N - 1); - si_int abs_a = (a ^ sa) - sa; - si_int sb = b >> (N - 1); - si_int abs_b = (b ^ sb) - sb; - if (abs_a < 2 || abs_b < 2) - return result; - if (sa == sb) { - if (abs_a > MAX / abs_b) - *overflow = 1; - } else { - if (abs_a > MIN / -abs_b) - *overflow = 1; - } - return result; + return __muloXi4(a, b, overflow); } diff --git a/system/lib/compiler-rt/lib/builtins/muloti4.c b/system/lib/compiler-rt/lib/builtins/muloti4.c index 9bdd5b649908b..9a7aa85b022bf 100644 --- a/system/lib/compiler-rt/lib/builtins/muloti4.c +++ b/system/lib/compiler-rt/lib/builtins/muloti4.c @@ -18,36 +18,11 @@ // Effects: sets *overflow to 1 if a * b overflows +#define fixint_t ti_int +#include "int_mulo_impl.inc" + COMPILER_RT_ABI ti_int __muloti4(ti_int a, ti_int b, int *overflow) { - const int N = (int)(sizeof(ti_int) * CHAR_BIT); - const ti_int MIN = (ti_int)1 << (N - 1); - const ti_int MAX = ~MIN; - *overflow = 0; - ti_int result = a * b; - if (a == MIN) { - if (b != 0 && b != 1) - *overflow = 1; - return result; - } - if (b == MIN) { - if (a != 0 && a != 1) - *overflow = 1; - return result; - } - ti_int sa = a >> (N - 1); - ti_int abs_a = (a ^ sa) - sa; - ti_int sb = b >> (N - 1); - ti_int abs_b = (b ^ sb) - sb; - if (abs_a < 2 || abs_b < 2) - return result; - if (sa == sb) { - if (abs_a > MAX / abs_b) - *overflow = 1; - } else { - if (abs_a > MIN / -abs_b) - *overflow = 1; - } - return result; + return __muloXi4(a, b, overflow); } #endif // CRT_HAS_128BIT diff --git a/system/lib/compiler-rt/lib/builtins/mulvdi3.c b/system/lib/compiler-rt/lib/builtins/mulvdi3.c index cecc97ccf22ec..1d672c6dc155d 100644 --- a/system/lib/compiler-rt/lib/builtins/mulvdi3.c +++ b/system/lib/compiler-rt/lib/builtins/mulvdi3.c @@ -10,38 +10,11 @@ // //===----------------------------------------------------------------------===// -#include "int_lib.h" +#define fixint_t di_int +#include "int_mulv_impl.inc" // Returns: a * b // Effects: aborts if a * b overflows -COMPILER_RT_ABI di_int __mulvdi3(di_int a, di_int b) { - const int N = (int)(sizeof(di_int) * CHAR_BIT); - const di_int MIN = (di_int)1 << (N - 1); - const di_int MAX = ~MIN; - if (a == MIN) { - if (b == 0 || b == 1) - return a * b; - compilerrt_abort(); - } - if (b == MIN) { - if (a == 0 || a == 1) - return a * b; - compilerrt_abort(); - } - di_int sa = a >> (N - 1); - di_int abs_a = (a ^ sa) - sa; - di_int sb = b >> (N - 1); - di_int abs_b = (b ^ sb) - sb; - if (abs_a < 2 || abs_b < 2) - return a * b; - if (sa == sb) { - if (abs_a > MAX / abs_b) - compilerrt_abort(); - } else { - if (abs_a > MIN / -abs_b) - compilerrt_abort(); - } - return a * b; -} +COMPILER_RT_ABI di_int __mulvdi3(di_int a, di_int b) { return __mulvXi3(a, b); } diff --git a/system/lib/compiler-rt/lib/builtins/mulvsi3.c b/system/lib/compiler-rt/lib/builtins/mulvsi3.c index 0d6b18ad01a40..00b2e50eeca91 100644 --- a/system/lib/compiler-rt/lib/builtins/mulvsi3.c +++ b/system/lib/compiler-rt/lib/builtins/mulvsi3.c @@ -10,38 +10,11 @@ // //===----------------------------------------------------------------------===// -#include "int_lib.h" +#define fixint_t si_int +#include "int_mulv_impl.inc" // Returns: a * b // Effects: aborts if a * b overflows -COMPILER_RT_ABI si_int __mulvsi3(si_int a, si_int b) { - const int N = (int)(sizeof(si_int) * CHAR_BIT); - const si_int MIN = (si_int)1 << (N - 1); - const si_int MAX = ~MIN; - if (a == MIN) { - if (b == 0 || b == 1) - return a * b; - compilerrt_abort(); - } - if (b == MIN) { - if (a == 0 || a == 1) - return a * b; - compilerrt_abort(); - } - si_int sa = a >> (N - 1); - si_int abs_a = (a ^ sa) - sa; - si_int sb = b >> (N - 1); - si_int abs_b = (b ^ sb) - sb; - if (abs_a < 2 || abs_b < 2) - return a * b; - if (sa == sb) { - if (abs_a > MAX / abs_b) - compilerrt_abort(); - } else { - if (abs_a > MIN / -abs_b) - compilerrt_abort(); - } - return a * b; -} +COMPILER_RT_ABI si_int __mulvsi3(si_int a, si_int b) { return __mulvXi3(a, b); } diff --git a/system/lib/compiler-rt/lib/builtins/mulvti3.c b/system/lib/compiler-rt/lib/builtins/mulvti3.c index 03963a0ca694f..ba355149f9a76 100644 --- a/system/lib/compiler-rt/lib/builtins/mulvti3.c +++ b/system/lib/compiler-rt/lib/builtins/mulvti3.c @@ -18,34 +18,9 @@ // Effects: aborts if a * b overflows -COMPILER_RT_ABI ti_int __mulvti3(ti_int a, ti_int b) { - const int N = (int)(sizeof(ti_int) * CHAR_BIT); - const ti_int MIN = (ti_int)1 << (N - 1); - const ti_int MAX = ~MIN; - if (a == MIN) { - if (b == 0 || b == 1) - return a * b; - compilerrt_abort(); - } - if (b == MIN) { - if (a == 0 || a == 1) - return a * b; - compilerrt_abort(); - } - ti_int sa = a >> (N - 1); - ti_int abs_a = (a ^ sa) - sa; - ti_int sb = b >> (N - 1); - ti_int abs_b = (b ^ sb) - sb; - if (abs_a < 2 || abs_b < 2) - return a * b; - if (sa == sb) { - if (abs_a > MAX / abs_b) - compilerrt_abort(); - } else { - if (abs_a > MIN / -abs_b) - compilerrt_abort(); - } - return a * b; -} +#define fixint_t ti_int +#include "int_mulv_impl.inc" + +COMPILER_RT_ABI ti_int __mulvti3(ti_int a, ti_int b) { return __mulvXi3(a, b); } #endif // CRT_HAS_128BIT diff --git a/system/lib/compiler-rt/lib/builtins/os_version_check.c b/system/lib/compiler-rt/lib/builtins/os_version_check.c index 3794b979434cc..d7194b99ae54c 100644 --- a/system/lib/compiler-rt/lib/builtins/os_version_check.c +++ b/system/lib/compiler-rt/lib/builtins/os_version_check.c @@ -24,6 +24,20 @@ // These three variables hold the host's OS version. static int32_t GlobalMajor, GlobalMinor, GlobalSubminor; static dispatch_once_t DispatchOnceCounter; +static dispatch_once_t CompatibilityDispatchOnceCounter; + +// _availability_version_check darwin API support. +typedef uint32_t dyld_platform_t; + +typedef struct { + dyld_platform_t platform; + uint32_t version; +} dyld_build_version_t; + +typedef bool (*AvailabilityVersionCheckFuncTy)(uint32_t count, + dyld_build_version_t versions[]); + +static AvailabilityVersionCheckFuncTy AvailabilityVersionCheck; // We can't include directly from here, so // just forward declare everything that we need from it. @@ -72,9 +86,25 @@ typedef Boolean (*CFStringGetCStringFuncTy)(CFStringRef, char *, CFIndex, CFStringEncoding); typedef void (*CFReleaseFuncTy)(CFTypeRef); -// Find and parse the SystemVersion.plist file. -static void parseSystemVersionPList(void *Unused) { - (void)Unused; +static void _initializeAvailabilityCheck(bool LoadPlist) { + if (AvailabilityVersionCheck && !LoadPlist) { + // New API is supported and we're not being asked to load the plist, + // exit early! + return; + } + + // Use the new API if it's is available. + AvailabilityVersionCheck = (AvailabilityVersionCheckFuncTy)dlsym( + RTLD_DEFAULT, "_availability_version_check"); + + if (AvailabilityVersionCheck && !LoadPlist) { + // New API is supported and we're not being asked to load the plist, + // exit early! + return; + } + // Still load the PLIST to ensure that the existing calls to + // __isOSVersionAtLeast still work even with new compiler-rt and old OSes. + // Load CoreFoundation dynamically const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull"); if (!NullAllocator) @@ -201,9 +231,24 @@ static void parseSystemVersionPList(void *Unused) { fclose(PropertyList); } +// Find and parse the SystemVersion.plist file. +static void compatibilityInitializeAvailabilityCheck(void *Unused) { + (void)Unused; + _initializeAvailabilityCheck(/*LoadPlist=*/true); +} + +static void initializeAvailabilityCheck(void *Unused) { + (void)Unused; + _initializeAvailabilityCheck(/*LoadPlist=*/false); +} + +// This old API entry point is no longer used by Clang for Darwin. We still need +// to keep it around to ensure that object files that reference it are still +// usable when linked with new compiler-rt. int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) { // Populate the global version variables, if they haven't already. - dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList); + dispatch_once_f(&CompatibilityDispatchOnceCounter, NULL, + compatibilityInitializeAvailabilityCheck); if (Major < GlobalMajor) return 1; @@ -216,6 +261,61 @@ int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) { return Subminor <= GlobalSubminor; } +static inline uint32_t ConstructVersion(uint32_t Major, uint32_t Minor, + uint32_t Subminor) { + return ((Major & 0xffff) << 16) | ((Minor & 0xff) << 8) | (Subminor & 0xff); +} + +int32_t __isPlatformVersionAtLeast(uint32_t Platform, uint32_t Major, + uint32_t Minor, uint32_t Subminor) { + dispatch_once_f(&DispatchOnceCounter, NULL, initializeAvailabilityCheck); + + if (!AvailabilityVersionCheck) { + return __isOSVersionAtLeast(Major, Minor, Subminor); + } + dyld_build_version_t Versions[] = { + {Platform, ConstructVersion(Major, Minor, Subminor)}}; + return AvailabilityVersionCheck(1, Versions); +} + +#elif __ANDROID__ + +#include +#include +#include +#include + +static int SdkVersion; +static int IsPreRelease; + +static void readSystemProperties(void) { + char buf[PROP_VALUE_MAX]; + + if (__system_property_get("ro.build.version.sdk", buf) == 0) { + // When the system property doesn't exist, defaults to future API level. + SdkVersion = __ANDROID_API_FUTURE__; + } else { + SdkVersion = atoi(buf); + } + + if (__system_property_get("ro.build.version.codename", buf) == 0) { + IsPreRelease = 1; + } else { + IsPreRelease = strcmp(buf, "REL") != 0; + } + return; +} + +int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) { + (int32_t) Minor; + (int32_t) Subminor; + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, readSystemProperties); + + return SdkVersion >= Major || + (IsPreRelease && Major == __ANDROID_API_FUTURE__); +} + #else // Silence an empty translation unit warning. diff --git a/system/lib/compiler-rt/lib/builtins/paritydi2.c b/system/lib/compiler-rt/lib/builtins/paritydi2.c index dd9d45e63ea47..350dceb8cef59 100644 --- a/system/lib/compiler-rt/lib/builtins/paritydi2.c +++ b/system/lib/compiler-rt/lib/builtins/paritydi2.c @@ -14,8 +14,12 @@ // Returns: 1 if number of bits is odd else returns 0 -COMPILER_RT_ABI si_int __paritydi2(di_int a) { +COMPILER_RT_ABI int __paritydi2(di_int a) { dwords x; x.all = a; - return __paritysi2(x.s.high ^ x.s.low); + su_int x2 = x.s.high ^ x.s.low; + x2 ^= x2 >> 16; + x2 ^= x2 >> 8; + x2 ^= x2 >> 4; + return (0x6996 >> (x2 & 0xF)) & 1; } diff --git a/system/lib/compiler-rt/lib/builtins/paritysi2.c b/system/lib/compiler-rt/lib/builtins/paritysi2.c index 3efa961f2f85f..a4b84e0806328 100644 --- a/system/lib/compiler-rt/lib/builtins/paritysi2.c +++ b/system/lib/compiler-rt/lib/builtins/paritysi2.c @@ -14,7 +14,7 @@ // Returns: 1 if number of bits is odd else returns 0 -COMPILER_RT_ABI si_int __paritysi2(si_int a) { +COMPILER_RT_ABI int __paritysi2(si_int a) { su_int x = (su_int)a; x ^= x >> 16; x ^= x >> 8; diff --git a/system/lib/compiler-rt/lib/builtins/parityti2.c b/system/lib/compiler-rt/lib/builtins/parityti2.c index f3942ba8378c7..011c8dd455620 100644 --- a/system/lib/compiler-rt/lib/builtins/parityti2.c +++ b/system/lib/compiler-rt/lib/builtins/parityti2.c @@ -16,10 +16,16 @@ // Returns: 1 if number of bits is odd else returns 0 -COMPILER_RT_ABI si_int __parityti2(ti_int a) { +COMPILER_RT_ABI int __parityti2(ti_int a) { twords x; + dwords x2; x.all = a; - return __paritydi2(x.s.high ^ x.s.low); + x2.all = x.s.high ^ x.s.low; + su_int x3 = x2.s.high ^ x2.s.low; + x3 ^= x3 >> 16; + x3 ^= x3 >> 8; + x3 ^= x3 >> 4; + return (0x6996 >> (x3 & 0xF)) & 1; } #endif // CRT_HAS_128BIT diff --git a/system/lib/compiler-rt/lib/builtins/popcountdi2.c b/system/lib/compiler-rt/lib/builtins/popcountdi2.c index 9bbc39c6608a1..20dd0b0239efc 100644 --- a/system/lib/compiler-rt/lib/builtins/popcountdi2.c +++ b/system/lib/compiler-rt/lib/builtins/popcountdi2.c @@ -14,7 +14,7 @@ // Returns: count of 1 bits -COMPILER_RT_ABI si_int __popcountdi2(di_int a) { +COMPILER_RT_ABI int __popcountdi2(di_int a) { du_int x2 = (du_int)a; x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL); // Every 2 bits holds the sum of every pair of bits (32) diff --git a/system/lib/compiler-rt/lib/builtins/popcountsi2.c b/system/lib/compiler-rt/lib/builtins/popcountsi2.c index 75e592a778d98..4d346c45d9cee 100644 --- a/system/lib/compiler-rt/lib/builtins/popcountsi2.c +++ b/system/lib/compiler-rt/lib/builtins/popcountsi2.c @@ -14,7 +14,7 @@ // Returns: count of 1 bits -COMPILER_RT_ABI si_int __popcountsi2(si_int a) { +COMPILER_RT_ABI int __popcountsi2(si_int a) { su_int x = (su_int)a; x = x - ((x >> 1) & 0x55555555); // Every 2 bits holds the sum of every pair of bits diff --git a/system/lib/compiler-rt/lib/builtins/popcountti2.c b/system/lib/compiler-rt/lib/builtins/popcountti2.c index 853fd722309ee..79cbb2fb34c00 100644 --- a/system/lib/compiler-rt/lib/builtins/popcountti2.c +++ b/system/lib/compiler-rt/lib/builtins/popcountti2.c @@ -17,7 +17,7 @@ // Returns: count of 1 bits -COMPILER_RT_ABI si_int __popcountti2(ti_int a) { +COMPILER_RT_ABI int __popcountti2(ti_int a) { tu_int x3 = (tu_int)a; x3 = x3 - ((x3 >> 1) & (((tu_int)0x5555555555555555uLL << 64) | 0x5555555555555555uLL)); diff --git a/system/lib/compiler-rt/lib/builtins/powidf2.c b/system/lib/compiler-rt/lib/builtins/powidf2.c index 9697588484e74..81058af508297 100644 --- a/system/lib/compiler-rt/lib/builtins/powidf2.c +++ b/system/lib/compiler-rt/lib/builtins/powidf2.c @@ -14,7 +14,7 @@ // Returns: a ^ b -COMPILER_RT_ABI double __powidf2(double a, si_int b) { +COMPILER_RT_ABI double __powidf2(double a, int b) { const int recip = b < 0; double r = 1; while (1) { diff --git a/system/lib/compiler-rt/lib/builtins/powisf2.c b/system/lib/compiler-rt/lib/builtins/powisf2.c index 469402348825c..d0ab26167bbd2 100644 --- a/system/lib/compiler-rt/lib/builtins/powisf2.c +++ b/system/lib/compiler-rt/lib/builtins/powisf2.c @@ -14,7 +14,7 @@ // Returns: a ^ b -COMPILER_RT_ABI float __powisf2(float a, si_int b) { +COMPILER_RT_ABI float __powisf2(float a, int b) { const int recip = b < 0; float r = 1; while (1) { diff --git a/system/lib/compiler-rt/lib/builtins/powitf2.c b/system/lib/compiler-rt/lib/builtins/powitf2.c index 443da04b29b19..8e639a03a3c4b 100644 --- a/system/lib/compiler-rt/lib/builtins/powitf2.c +++ b/system/lib/compiler-rt/lib/builtins/powitf2.c @@ -10,13 +10,14 @@ // //===----------------------------------------------------------------------===// -#include "int_lib.h" +#define QUAD_PRECISION +#include "fp_lib.h" -#if defined _ARCH_PPC || defined __wasm__ +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) // Returns: a ^ b -COMPILER_RT_ABI long double __powitf2(long double a, si_int b) { +COMPILER_RT_ABI long double __powitf2(long double a, int b) { const int recip = b < 0; long double r = 1; while (1) { diff --git a/system/lib/compiler-rt/lib/builtins/powixf2.c b/system/lib/compiler-rt/lib/builtins/powixf2.c index b7b52095afa17..3edfe9fd7af59 100644 --- a/system/lib/compiler-rt/lib/builtins/powixf2.c +++ b/system/lib/compiler-rt/lib/builtins/powixf2.c @@ -16,7 +16,7 @@ // Returns: a ^ b -COMPILER_RT_ABI long double __powixf2(long double a, si_int b) { +COMPILER_RT_ABI long double __powixf2(long double a, int b) { const int recip = b < 0; long double r = 1; while (1) { diff --git a/system/lib/compiler-rt/lib/builtins/truncdfhf2.c b/system/lib/compiler-rt/lib/builtins/truncdfhf2.c index 90c418a4387ff..24c6e62f715f5 100644 --- a/system/lib/compiler-rt/lib/builtins/truncdfhf2.c +++ b/system/lib/compiler-rt/lib/builtins/truncdfhf2.c @@ -10,11 +10,11 @@ #define DST_HALF #include "fp_trunc_impl.inc" -COMPILER_RT_ABI uint16_t __truncdfhf2(double a) { return __truncXfYf2__(a); } +COMPILER_RT_ABI dst_t __truncdfhf2(double a) { return __truncXfYf2__(a); } #if defined(__ARM_EABI__) #if defined(COMPILER_RT_ARMHF_TARGET) -AEABI_RTABI uint16_t __aeabi_d2h(double a) { return __truncdfhf2(a); } +AEABI_RTABI dst_t __aeabi_d2h(double a) { return __truncdfhf2(a); } #else COMPILER_RT_ALIAS(__truncdfhf2, __aeabi_d2h) #endif diff --git a/system/lib/compiler-rt/lib/builtins/truncsfhf2.c b/system/lib/compiler-rt/lib/builtins/truncsfhf2.c index 1f17194c38e59..379e7cb6f7845 100644 --- a/system/lib/compiler-rt/lib/builtins/truncsfhf2.c +++ b/system/lib/compiler-rt/lib/builtins/truncsfhf2.c @@ -12,15 +12,15 @@ // Use a forwarding definition and noinline to implement a poor man's alias, // as there isn't a good cross-platform way of defining one. -COMPILER_RT_ABI NOINLINE uint16_t __truncsfhf2(float a) { +COMPILER_RT_ABI NOINLINE dst_t __truncsfhf2(float a) { return __truncXfYf2__(a); } -COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(float a) { return __truncsfhf2(a); } +COMPILER_RT_ABI dst_t __gnu_f2h_ieee(float a) { return __truncsfhf2(a); } #if defined(__ARM_EABI__) #if defined(COMPILER_RT_ARMHF_TARGET) -AEABI_RTABI uint16_t __aeabi_f2h(float a) { return __truncsfhf2(a); } +AEABI_RTABI dst_t __aeabi_f2h(float a) { return __truncsfhf2(a); } #else COMPILER_RT_ALIAS(__truncsfhf2, __aeabi_f2h) #endif diff --git a/system/lib/compiler-rt/lib/builtins/trunctfhf2.c b/system/lib/compiler-rt/lib/builtins/trunctfhf2.c new file mode 100644 index 0000000000000..e3a2309d954bc --- /dev/null +++ b/system/lib/compiler-rt/lib/builtins/trunctfhf2.c @@ -0,0 +1,23 @@ +//===-- lib/trunctfhf2.c - quad -> half conversion ----------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define QUAD_PRECISION +#include "fp_lib.h" + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) && \ + defined(COMPILER_RT_HAS_FLOAT16) +#define SRC_QUAD +#define DST_HALF +#include "fp_trunc_impl.inc" + +COMPILER_RT_ABI _Float16 __trunctfhf2(long double a) { + return __truncXfYf2__(a); +} + +#endif diff --git a/system/lib/compiler-rt/lib/builtins/udivdi3.c b/system/lib/compiler-rt/lib/builtins/udivdi3.c index a23139ec947f6..74319cbe71c3b 100644 --- a/system/lib/compiler-rt/lib/builtins/udivdi3.c +++ b/system/lib/compiler-rt/lib/builtins/udivdi3.c @@ -12,8 +12,12 @@ #include "int_lib.h" +typedef du_int fixuint_t; +typedef di_int fixint_t; +#include "int_div_impl.inc" + // Returns: a / b COMPILER_RT_ABI du_int __udivdi3(du_int a, du_int b) { - return __udivmoddi4(a, b, 0); + return __udivXi3(a, b); } diff --git a/system/lib/compiler-rt/lib/builtins/udivmoddi4.c b/system/lib/compiler-rt/lib/builtins/udivmoddi4.c index 5b297c32d7901..10b41df28f840 100644 --- a/system/lib/compiler-rt/lib/builtins/udivmoddi4.c +++ b/system/lib/compiler-rt/lib/builtins/udivmoddi4.c @@ -87,7 +87,7 @@ COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) { // K K // --- // K 0 - sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + sr = clzsi(d.s.high) - clzsi(n.s.high); // 0 <= sr <= n_uword_bits - 2 or sr large if (sr > n_uword_bits - 2) { if (rem) @@ -120,7 +120,7 @@ COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) { // K X // --- // 0 K - sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high); + sr = 1 + n_uword_bits + clzsi(d.s.low) - clzsi(n.s.high); // 2 <= sr <= n_udword_bits - 1 // q.all = n.all << (n_udword_bits - sr); // r.all = n.all >> sr; @@ -145,7 +145,7 @@ COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) { // K X // --- // K K - sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + sr = clzsi(d.s.high) - clzsi(n.s.high); // 0 <= sr <= n_uword_bits - 1 or sr large if (sr > n_uword_bits - 1) { if (rem) diff --git a/system/lib/compiler-rt/lib/builtins/udivmodti4.c b/system/lib/compiler-rt/lib/builtins/udivmodti4.c index dd14a8b579ca5..55def37c9e1fe 100644 --- a/system/lib/compiler-rt/lib/builtins/udivmodti4.c +++ b/system/lib/compiler-rt/lib/builtins/udivmodti4.c @@ -14,182 +14,145 @@ #ifdef CRT_HAS_128BIT +// Returns the 128 bit division result by 64 bit. Result must fit in 64 bits. +// Remainder stored in r. +// Taken and adjusted from libdivide libdivide_128_div_64_to_64 division +// fallback. For a correctness proof see the reference for this algorithm +// in Knuth, Volume 2, section 4.3.1, Algorithm D. +UNUSED +static inline du_int udiv128by64to64default(du_int u1, du_int u0, du_int v, + du_int *r) { + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + const du_int b = (1ULL << (n_udword_bits / 2)); // Number base (32 bits) + du_int un1, un0; // Norm. dividend LSD's + du_int vn1, vn0; // Norm. divisor digits + du_int q1, q0; // Quotient digits + du_int un64, un21, un10; // Dividend digit pairs + du_int rhat; // A remainder + si_int s; // Shift amount for normalization + + s = __builtin_clzll(v); + if (s > 0) { + // Normalize the divisor. + v = v << s; + un64 = (u1 << s) | (u0 >> (n_udword_bits - s)); + un10 = u0 << s; // Shift dividend left + } else { + // Avoid undefined behavior of (u0 >> 64). + un64 = u1; + un10 = u0; + } + + // Break divisor up into two 32-bit digits. + vn1 = v >> (n_udword_bits / 2); + vn0 = v & 0xFFFFFFFF; + + // Break right half of dividend into two digits. + un1 = un10 >> (n_udword_bits / 2); + un0 = un10 & 0xFFFFFFFF; + + // Compute the first quotient digit, q1. + q1 = un64 / vn1; + rhat = un64 - q1 * vn1; + + // q1 has at most error 2. No more than 2 iterations. + while (q1 >= b || q1 * vn0 > b * rhat + un1) { + q1 = q1 - 1; + rhat = rhat + vn1; + if (rhat >= b) + break; + } + + un21 = un64 * b + un1 - q1 * v; + + // Compute the second quotient digit. + q0 = un21 / vn1; + rhat = un21 - q0 * vn1; + + // q0 has at most error 2. No more than 2 iterations. + while (q0 >= b || q0 * vn0 > b * rhat + un0) { + q0 = q0 - 1; + rhat = rhat + vn1; + if (rhat >= b) + break; + } + + *r = (un21 * b + un0 - q0 * v) >> s; + return q1 * b + q0; +} + +static inline du_int udiv128by64to64(du_int u1, du_int u0, du_int v, + du_int *r) { +#if defined(__x86_64__) + du_int result; + __asm__("divq %[v]" + : "=a"(result), "=d"(*r) + : [ v ] "r"(v), "a"(u0), "d"(u1)); + return result; +#else + return udiv128by64to64default(u1, u0, v, r); +#endif +} + // Effects: if rem != 0, *rem = a % b // Returns: a / b -// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide - COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem) { - const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT; - utwords n; - n.all = a; - utwords d; - d.all = b; - utwords q; - utwords r; - unsigned sr; - // special cases, X is unknown, K != 0 - if (n.s.high == 0) { - if (d.s.high == 0) { - // 0 X - // --- - // 0 X - if (rem) - *rem = n.s.low % d.s.low; - return n.s.low / d.s.low; - } - // 0 X - // --- - // K X + utwords dividend; + dividend.all = a; + utwords divisor; + divisor.all = b; + utwords quotient; + utwords remainder; + if (divisor.all > dividend.all) { if (rem) - *rem = n.s.low; + *rem = dividend.all; return 0; } - // n.s.high != 0 - if (d.s.low == 0) { - if (d.s.high == 0) { - // K X - // --- - // 0 0 - if (rem) - *rem = n.s.high % d.s.low; - return n.s.high / d.s.low; - } - // d.s.high != 0 - if (n.s.low == 0) { - // K 0 - // --- - // K 0 - if (rem) { - r.s.high = n.s.high % d.s.high; - r.s.low = 0; - *rem = r.all; - } - return n.s.high / d.s.high; - } - // K K - // --- - // K 0 - if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ { - if (rem) { - r.s.low = n.s.low; - r.s.high = n.s.high & (d.s.high - 1); - *rem = r.all; - } - return n.s.high >> __builtin_ctzll(d.s.high); - } - // K K - // --- - // K 0 - sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high); - // 0 <= sr <= n_udword_bits - 2 or sr large - if (sr > n_udword_bits - 2) { - if (rem) - *rem = n.all; - return 0; - } - ++sr; - // 1 <= sr <= n_udword_bits - 1 - // q.all = n.all << (n_utword_bits - sr); - q.s.low = 0; - q.s.high = n.s.low << (n_udword_bits - sr); - // r.all = n.all >> sr; - r.s.high = n.s.high >> sr; - r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); - } else /* d.s.low != 0 */ { - if (d.s.high == 0) { - // K X - // --- - // 0 K - if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ { - if (rem) - *rem = n.s.low & (d.s.low - 1); - if (d.s.low == 1) - return n.all; - sr = __builtin_ctzll(d.s.low); - q.s.high = n.s.high >> sr; - q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); - return q.all; - } - // K X - // --- - // 0 K - sr = 1 + n_udword_bits + __builtin_clzll(d.s.low) - - __builtin_clzll(n.s.high); - // 2 <= sr <= n_utword_bits - 1 - // q.all = n.all << (n_utword_bits - sr); - // r.all = n.all >> sr; - if (sr == n_udword_bits) { - q.s.low = 0; - q.s.high = n.s.low; - r.s.high = 0; - r.s.low = n.s.high; - } else if (sr < n_udword_bits) /* 2 <= sr <= n_udword_bits - 1 */ { - q.s.low = 0; - q.s.high = n.s.low << (n_udword_bits - sr); - r.s.high = n.s.high >> sr; - r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); - } else /* n_udword_bits + 1 <= sr <= n_utword_bits - 1 */ { - q.s.low = n.s.low << (n_utword_bits - sr); - q.s.high = (n.s.high << (n_utword_bits - sr)) | - (n.s.low >> (sr - n_udword_bits)); - r.s.high = 0; - r.s.low = n.s.high >> (sr - n_udword_bits); - } + // When the divisor fits in 64 bits, we can use an optimized path. + if (divisor.s.high == 0) { + remainder.s.high = 0; + if (dividend.s.high < divisor.s.low) { + // The result fits in 64 bits. + quotient.s.low = udiv128by64to64(dividend.s.high, dividend.s.low, + divisor.s.low, &remainder.s.low); + quotient.s.high = 0; } else { - // K X - // --- - // K K - sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high); - // 0 <= sr <= n_udword_bits - 1 or sr large - if (sr > n_udword_bits - 1) { - if (rem) - *rem = n.all; - return 0; - } - ++sr; - // 1 <= sr <= n_udword_bits - // q.all = n.all << (n_utword_bits - sr); - // r.all = n.all >> sr; - q.s.low = 0; - if (sr == n_udword_bits) { - q.s.high = n.s.low; - r.s.high = 0; - r.s.low = n.s.high; - } else { - r.s.high = n.s.high >> sr; - r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); - q.s.high = n.s.low << (n_udword_bits - sr); - } + // First, divide with the high part to get the remainder in dividend.s.high. + // After that dividend.s.high < divisor.s.low. + quotient.s.high = dividend.s.high / divisor.s.low; + dividend.s.high = dividend.s.high % divisor.s.low; + quotient.s.low = udiv128by64to64(dividend.s.high, dividend.s.low, + divisor.s.low, &remainder.s.low); } + if (rem) + *rem = remainder.all; + return quotient.all; } - // Not a special case - // q and r are initialized with: - // q.all = n.all << (n_utword_bits - sr); - // r.all = n.all >> sr; - // 1 <= sr <= n_utword_bits - 1 - su_int carry = 0; - for (; sr > 0; --sr) { - // r:q = ((r:q) << 1) | carry - r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1)); - r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1)); - q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1)); - q.s.low = (q.s.low << 1) | carry; - // carry = 0; - // if (r.all >= d.all) + // 0 <= shift <= 63. + si_int shift = + __builtin_clzll(divisor.s.high) - __builtin_clzll(dividend.s.high); + divisor.all <<= shift; + quotient.s.high = 0; + quotient.s.low = 0; + for (; shift >= 0; --shift) { + quotient.s.low <<= 1; + // Branch free version of. + // if (dividend.all >= divisor.all) // { - // r.all -= d.all; - // carry = 1; + // dividend.all -= divisor.all; + // carry = 1; // } - const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1); - carry = s & 1; - r.all -= d.all & s; + const ti_int s = + (ti_int)(divisor.all - dividend.all - 1) >> (n_utword_bits - 1); + quotient.s.low |= s & 1; + dividend.all -= divisor.all & s; + divisor.all >>= 1; } - q.all = (q.all << 1) | carry; if (rem) - *rem = r.all; - return q.all; + *rem = dividend.all; + return quotient.all; } #endif // CRT_HAS_128BIT diff --git a/system/lib/compiler-rt/lib/builtins/udivsi3.c b/system/lib/compiler-rt/lib/builtins/udivsi3.c index 18cc96c1b2e08..3894e1597552f 100644 --- a/system/lib/compiler-rt/lib/builtins/udivsi3.c +++ b/system/lib/compiler-rt/lib/builtins/udivsi3.c @@ -12,49 +12,14 @@ #include "int_lib.h" -// Returns: a / b +typedef su_int fixuint_t; +typedef si_int fixint_t; +#include "int_div_impl.inc" -// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide +// Returns: a / b -// This function should not call __divsi3! -COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d) { - const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; - su_int q; - su_int r; - unsigned sr; - // special cases - if (d == 0) - return 0; // ?! - if (n == 0) - return 0; - sr = __builtin_clz(d) - __builtin_clz(n); - // 0 <= sr <= n_uword_bits - 1 or sr large - if (sr > n_uword_bits - 1) // d > r - return 0; - if (sr == n_uword_bits - 1) // d == 1 - return n; - ++sr; - // 1 <= sr <= n_uword_bits - 1 - // Not a special case - q = n << (n_uword_bits - sr); - r = n >> sr; - su_int carry = 0; - for (; sr > 0; --sr) { - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> (n_uword_bits - 1)); - q = (q << 1) | carry; - // carry = 0; - // if (r.all >= d.all) - // { - // r.all -= d.all; - // carry = 1; - // } - const si_int s = (si_int)(d - r - 1) >> (n_uword_bits - 1); - carry = s & 1; - r -= d & s; - } - q = (q << 1) | carry; - return q; +COMPILER_RT_ABI su_int __udivsi3(su_int a, su_int b) { + return __udivXi3(a, b); } #if defined(__ARM_EABI__) diff --git a/system/lib/compiler-rt/lib/builtins/umoddi3.c b/system/lib/compiler-rt/lib/builtins/umoddi3.c index 965cf8fc01bd2..e672da96ef629 100644 --- a/system/lib/compiler-rt/lib/builtins/umoddi3.c +++ b/system/lib/compiler-rt/lib/builtins/umoddi3.c @@ -12,10 +12,12 @@ #include "int_lib.h" +typedef du_int fixuint_t; +typedef di_int fixint_t; +#include "int_div_impl.inc" + // Returns: a % b COMPILER_RT_ABI du_int __umoddi3(du_int a, du_int b) { - du_int r; - __udivmoddi4(a, b, &r); - return r; + return __umodXi3(a, b); } diff --git a/system/lib/compiler-rt/lib/builtins/umodsi3.c b/system/lib/compiler-rt/lib/builtins/umodsi3.c index ce9abcd94ef77..5383aea656a99 100644 --- a/system/lib/compiler-rt/lib/builtins/umodsi3.c +++ b/system/lib/compiler-rt/lib/builtins/umodsi3.c @@ -12,8 +12,12 @@ #include "int_lib.h" +typedef su_int fixuint_t; +typedef si_int fixint_t; +#include "int_div_impl.inc" + // Returns: a % b COMPILER_RT_ABI su_int __umodsi3(su_int a, su_int b) { - return a - __udivsi3(a, b) * b; + return __umodXi3(a, b); } diff --git a/system/lib/compiler-rt/lib/interception/interception.h b/system/lib/compiler-rt/lib/interception/interception.h index aa2986b1c92fa..c69a63963798d 100644 --- a/system/lib/compiler-rt/lib/interception/interception.h +++ b/system/lib/compiler-rt/lib/interception/interception.h @@ -17,7 +17,7 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \ - !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_WINDOWS && \ + !SANITIZER_NETBSD && !SANITIZER_WINDOWS && \ !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS && \ !SANITIZER_EMSCRIPTEN # error "Interception doesn't work on this operating system." @@ -290,7 +290,7 @@ typedef unsigned long uptr; // NOLINT #define INCLUDED_FROM_INTERCEPTION_LIB #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN # include "interception_linux.h" # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) diff --git a/system/lib/compiler-rt/lib/interception/interception_linux.cpp b/system/lib/compiler-rt/lib/interception/interception_linux.cpp index 950cd5126538b..5111a87f0a6c9 100644 --- a/system/lib/compiler-rt/lib/interception/interception_linux.cpp +++ b/system/lib/compiler-rt/lib/interception/interception_linux.cpp @@ -14,7 +14,7 @@ #include "interception.h" #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS + SANITIZER_SOLARIS #include // for dlsym() and dlvsym() @@ -63,8 +63,8 @@ bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func, return addr && (func == wrapper); } -// Android and Solaris do not have dlvsym -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD +// dlvsym is a GNU extension supported by some other platforms. +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD static void *GetFuncAddr(const char *name, const char *ver) { return dlvsym(RTLD_NEXT, name, ver); } @@ -75,9 +75,9 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, *ptr_to_real = (uptr)addr; return addr && (func == wrapper); } -#endif // !SANITIZER_ANDROID +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD } // namespace __interception #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || - // SANITIZER_OPENBSD || SANITIZER_SOLARIS + // SANITIZER_SOLARIS diff --git a/system/lib/compiler-rt/lib/interception/interception_linux.h b/system/lib/compiler-rt/lib/interception/interception_linux.h index 5a98b57d01d7b..6d3957e570267 100644 --- a/system/lib/compiler-rt/lib/interception/interception_linux.h +++ b/system/lib/compiler-rt/lib/interception/interception_linux.h @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) # error "interception_linux.h should be included from interception library only" @@ -35,9 +35,8 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, (::__interception::uptr) & (func), \ (::__interception::uptr) & WRAP(func)) -// Android, Solaris, OpenBSD and emscripten do not have dlvsym -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD && \ - !SANITIZER_EMSCRIPTEN +// dlvsym is a GNU extension supported by some other platforms. +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ ::__interception::InterceptFunction( \ #func, symver, \ @@ -47,8 +46,8 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, #else #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) -#endif // !SANITIZER_ANDROID && !SANITIZER_SOLARIS +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD #endif // INTERCEPTION_LINUX_H #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || - // SANITIZER_OPENBSD || SANITIZER_SOLARIS + // SANITIZER_SOLARIS diff --git a/system/lib/compiler-rt/lib/interception/interception_win.cpp b/system/lib/compiler-rt/lib/interception/interception_win.cpp index 1a1c327e61240..98bc756ae53aa 100644 --- a/system/lib/compiler-rt/lib/interception/interception_win.cpp +++ b/system/lib/compiler-rt/lib/interception/interception_win.cpp @@ -136,7 +136,7 @@ namespace __interception { static const int kAddressLength = FIRST_32_SECOND_64(4, 8); static const int kJumpInstructionLength = 5; static const int kShortJumpInstructionLength = 2; -static const int kIndirectJumpInstructionLength = 6; +UNUSED static const int kIndirectJumpInstructionLength = 6; static const int kBranchLength = FIRST_32_SECOND_64(kJumpInstructionLength, kIndirectJumpInstructionLength); static const int kDirectBranchLength = kBranchLength + kAddressLength; @@ -165,7 +165,7 @@ static uptr GetMmapGranularity() { return si.dwAllocationGranularity; } -static uptr RoundUpTo(uptr size, uptr boundary) { +UNUSED static uptr RoundUpTo(uptr size, uptr boundary) { return (size + boundary - 1) & ~(boundary - 1); } @@ -309,7 +309,7 @@ struct TrampolineMemoryRegion { uptr max_size; }; -static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig +UNUSED static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig static const int kMaxTrampolineRegion = 1024; static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion]; diff --git a/system/lib/compiler-rt/lib/lsan/lsan.cpp b/system/lib/compiler-rt/lib/lsan/lsan.cpp index 8e3f0294eea04..e1e33c068e1fe 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan.cpp @@ -15,7 +15,6 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" -#include "sanitizer_common/sanitizer_stacktrace.h" #include "lsan_allocator.h" #include "lsan_common.h" #include "lsan_thread.h" @@ -83,7 +82,7 @@ static void InitializeFlags() { RegisterCommonFlags(&parser); // Override from user-specified string. - const char *lsan_default_options = MaybeCallLsanDefaultOptions(); + const char *lsan_default_options = __lsan_default_options(); parser.ParseString(lsan_default_options); #if SANITIZER_EMSCRIPTEN char *options = (char*) EM_ASM_INT({ @@ -102,7 +101,7 @@ static void InitializeFlags() { StackTrace::snapshot_stack = false; #endif // SANITIZER_EMSCRIPTEN - SetVerbosity(common_flags()->verbosity); + InitializeCommonFlags(); if (Verbosity()) ReportUnrecognizedFlags(); @@ -111,17 +110,6 @@ static void InitializeFlags() { __sanitizer_set_report_path(common_flags()->log_path); } -static void OnStackUnwind(const SignalContext &sig, const void *, - BufferedStackTrace *stack) { - stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, - common_flags()->fast_unwind_on_fatal); -} - -static void LsanOnDeadlySignal(int signo, void *siginfo, void *context) { - HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind, - nullptr); -} - extern "C" void __lsan_init() { CHECK(!lsan_init_is_running); if (lsan_inited) @@ -141,10 +129,7 @@ extern "C" void __lsan_init() { // Emscripten does not have signals InstallDeadlySignalHandlers(LsanOnDeadlySignal); #endif - u32 tid = ThreadCreate(0, 0, true); - CHECK_EQ(tid, 0); - ThreadStart(tid, GetTid()); - SetCurrentThread(tid); + InitializeMainThread(); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) Atexit(DoLeakCheck); diff --git a/system/lib/compiler-rt/lib/lsan/lsan.h b/system/lib/compiler-rt/lib/lsan/lsan.h index 9904ada4bb3bd..1e82ad72f0058 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan.h +++ b/system/lib/compiler-rt/lib/lsan/lsan.h @@ -12,6 +12,11 @@ //===----------------------------------------------------------------------===// #include "lsan_thread.h" +#if SANITIZER_POSIX +#include "lsan_posix.h" +#elif SANITIZER_FUCHSIA +#include "lsan_fuchsia.h" +#endif #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_stacktrace.h" @@ -33,6 +38,7 @@ namespace __lsan { void InitializeInterceptors(); void ReplaceSystemMalloc(); +void LsanOnDeadlySignal(int signo, void *siginfo, void *context); #define ENSURE_LSAN_INITED do { \ CHECK(!lsan_init_is_running); \ diff --git a/system/lib/compiler-rt/lib/lsan/lsan_allocator.cpp b/system/lib/compiler-rt/lib/lsan/lsan_allocator.cpp index 845526a8771a1..5dff571e4a059 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_allocator.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_allocator.cpp @@ -309,6 +309,16 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) { return kIgnoreObjectInvalid; } } + +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) { + // This function can be used to treat memory reachable from `tctx` as live. + // This is useful for threads that have been created but not yet started. + + // This is currently a no-op because the LSan `pthread_create()` interceptor + // blocks until the child thread starts which keeps the thread's `arg` pointer + // live. +} + } // namespace __lsan using namespace __lsan; diff --git a/system/lib/compiler-rt/lib/lsan/lsan_allocator.h b/system/lib/compiler-rt/lib/lsan/lsan_allocator.h index 3df5f77bd3bcf..050a9143bc014 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_allocator.h +++ b/system/lib/compiler-rt/lib/lsan/lsan_allocator.h @@ -72,10 +72,16 @@ struct AP32 { template using PrimaryAllocatorASVT = SizeClassAllocator32>; using PrimaryAllocator = PrimaryAllocatorASVT; -#elif defined(__x86_64__) || defined(__powerpc64__) -# if defined(__powerpc64__) +#elif defined(__x86_64__) || defined(__powerpc64__) || defined(__s390x__) +# if SANITIZER_FUCHSIA +const uptr kAllocatorSpace = ~(uptr)0; +const uptr kAllocatorSize = 0x40000000000ULL; // 4T. +# elif defined(__powerpc64__) const uptr kAllocatorSpace = 0xa0000000000ULL; const uptr kAllocatorSize = 0x20000000000ULL; // 2T. +#elif defined(__s390x__) +const uptr kAllocatorSpace = 0x40000000000ULL; +const uptr kAllocatorSize = 0x40000000000ULL; // 4T. # else const uptr kAllocatorSpace = 0x600000000000ULL; const uptr kAllocatorSize = 0x40000000000ULL; // 4T. diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common.cpp index fdd53733241b5..50a2e1952ecd6 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_common.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_common.cpp @@ -1,4 +1,4 @@ -//=-- lsan_common.cc ------------------------------------------------------===// +//=-- lsan_common.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -38,6 +38,7 @@ BlockingMutex global_mutex(LINKER_INITIALIZED); Flags lsan_flags; + void DisableCounterUnderflow() { if (common_flags()->detect_leaks) { Report("Unmatched call to __lsan_enable().\n"); @@ -68,35 +69,67 @@ void RegisterLsanFlags(FlagParser *parser, Flags *f) { if (flags()->log_threads) Report(__VA_ARGS__); \ } while (0) -ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; -static SuppressionContext *suppression_ctx = nullptr; +class LeakSuppressionContext { + bool parsed = false; + SuppressionContext context; + bool suppressed_stacks_sorted = true; + InternalMmapVector suppressed_stacks; + + Suppression *GetSuppressionForAddr(uptr addr); + void LazyInit(); + + public: + LeakSuppressionContext(const char *supprression_types[], + int suppression_types_num) + : context(supprression_types, suppression_types_num) {} + + Suppression *GetSuppressionForStack(u32 stack_trace_id); + + const InternalMmapVector &GetSortedSuppressedStacks() { + if (!suppressed_stacks_sorted) { + suppressed_stacks_sorted = true; + SortAndDedup(suppressed_stacks); + } + return suppressed_stacks; + } + void PrintMatchedSuppressions(); +}; + +ALIGNED(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)]; +static LeakSuppressionContext *suppression_ctx = nullptr; static const char kSuppressionLeak[] = "leak"; static const char *kSuppressionTypes[] = { kSuppressionLeak }; static const char kStdSuppressions[] = #if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT - // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT - // definition. - "leak:*pthread_exit*\n" + // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT + // definition. + "leak:*pthread_exit*\n" #endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT #if SANITIZER_MAC - // For Darwin and os_log/os_trace: https://reviews.llvm.org/D35173 - "leak:*_os_trace*\n" + // For Darwin and os_log/os_trace: https://reviews.llvm.org/D35173 + "leak:*_os_trace*\n" #endif - // TLS leak in some glibc versions, described in - // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. - "leak:*tls_get_addr*\n"; + // TLS leak in some glibc versions, described in + // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. + "leak:*tls_get_addr*\n"; void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); suppression_ctx = new (suppression_placeholder) // NOLINT - SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); - suppression_ctx->ParseFromFile(flags()->suppressions); - if (&__lsan_default_suppressions) - suppression_ctx->Parse(__lsan_default_suppressions()); - suppression_ctx->Parse(kStdSuppressions); + LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); } -static SuppressionContext *GetSuppressionContext() { +void LeakSuppressionContext::LazyInit() { + if (!parsed) { + parsed = true; + context.ParseFromFile(flags()->suppressions); + if (&__lsan_default_suppressions) + context.Parse(__lsan_default_suppressions()); + context.Parse(kStdSuppressions); + } +} + +static LeakSuppressionContext *GetSuppressionContext() { CHECK(suppression_ctx); return suppression_ctx; } @@ -111,10 +144,6 @@ void InitializeRootRegions() { root_regions = new (placeholder) InternalMmapVector(); } -const char *MaybeCallLsanDefaultOptions() { - return (&__lsan_default_options) ? __lsan_default_options() : ""; -} - void InitCommonLsan() { InitializeRootRegions(); if (common_flags()->detect_leaks) { @@ -232,14 +261,45 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) { ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable); } +#if SANITIZER_FUCHSIA + +// Fuchsia handles all threads together with its own callback. +static void ProcessThreads(SuspendedThreadsList const &, Frontier *) {} + +#else + +#if SANITIZER_ANDROID +// FIXME: Move this out into *libcdep.cpp +extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls( + pid_t, void (*cb)(void *, void *, uptr, void *), void *); +#endif + +static void ProcessThreadRegistry(Frontier *frontier) { + InternalMmapVector ptrs; + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked( + GetAdditionalThreadContextPtrs, &ptrs); + + for (uptr i = 0; i < ptrs.size(); ++i) { + void *ptr = reinterpret_cast(ptrs[i]); + uptr chunk = PointsIntoChunk(ptr); + if (!chunk) + continue; + LsanMetadata m(chunk); + if (!m.allocated()) + continue; + + // Mark as reachable and add to frontier. + LOG_POINTERS("Treating pointer %p from ThreadContext as reachable\n", ptr); + m.set_tag(kReachable); + frontier->push_back(chunk); + } +} + #if !SANITIZER_EMSCRIPTEN // Scans thread data (stacks and TLS) for heap pointers. -void ProcessThreads(SuspendedThreadsList const &suspended_threads, - Frontier *frontier) { - InternalMmapVector registers(suspended_threads.RegisterCount()); - uptr registers_begin = reinterpret_cast(registers.data()); - uptr registers_end = - reinterpret_cast(registers.data() + registers.size()); +static void ProcessThreads(SuspendedThreadsList const &suspended_threads, + Frontier *frontier) { + InternalMmapVector registers; for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) { tid_t os_id = static_cast(suspended_threads.GetThreadID(i)); LOG_THREADS("Processing thread %d.\n", os_id); @@ -256,7 +316,7 @@ void ProcessThreads(SuspendedThreadsList const &suspended_threads, } uptr sp; PtraceRegistersStatus have_registers = - suspended_threads.GetRegistersAndSP(i, registers.data(), &sp); + suspended_threads.GetRegistersAndSP(i, ®isters, &sp); if (have_registers != REGISTERS_AVAILABLE) { Report("Unable to get registers from thread %d.\n", os_id); // If unable to get SP, consider the entire stack to be reachable unless @@ -265,9 +325,13 @@ void ProcessThreads(SuspendedThreadsList const &suspended_threads, sp = stack_begin; } - if (flags()->use_registers && have_registers) + if (flags()->use_registers && have_registers) { + uptr registers_begin = reinterpret_cast(registers.data()); + uptr registers_end = + reinterpret_cast(registers.data() + registers.size()); ScanRangeForPointers(registers_begin, registers_end, frontier, "REGISTERS", kReachable); + } if (flags()->use_stacks) { LOG_THREADS("Stack at %p-%p (SP = %p).\n", stack_begin, stack_end, sp); @@ -311,26 +375,46 @@ void ProcessThreads(SuspendedThreadsList const &suspended_threads, kReachable); } } +#if SANITIZER_ANDROID + auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /*dso_idd*/, + void *arg) -> void { + ScanRangeForPointers(reinterpret_cast(dtls_begin), + reinterpret_cast(dtls_end), + reinterpret_cast(arg), "DTLS", + kReachable); + }; + + // FIXME: There might be a race-condition here (and in Bionic) if the + // thread is suspended in the middle of updating its DTLS. IOWs, we + // could scan already freed memory. (probably fine for now) + __libc_iterate_dynamic_tls(os_id, cb, frontier); +#else if (dtls && !DTLSInDestruction(dtls)) { - for (uptr j = 0; j < dtls->dtv_size; ++j) { - uptr dtls_beg = dtls->dtv[j].beg; - uptr dtls_end = dtls_beg + dtls->dtv[j].size; + ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) { + uptr dtls_beg = dtv.beg; + uptr dtls_end = dtls_beg + dtv.size; if (dtls_beg < dtls_end) { - LOG_THREADS("DTLS %zu at %p-%p.\n", j, dtls_beg, dtls_end); + LOG_THREADS("DTLS %zu at %p-%p.\n", id, dtls_beg, dtls_end); ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS", kReachable); } - } + }); } else { // We are handling a thread with DTLS under destruction. Log about // this and continue. LOG_THREADS("Thread %d has DTLS under destruction.\n", os_id); } +#endif } } + + // Add pointers reachable from ThreadContexts + ProcessThreadRegistry(frontier); } #endif // !SANITIZER_EMSCRIPTEN +#endif // SANITIZER_FUCHSIA + void ScanRootRegion(Frontier *frontier, const RootRegion &root_region, uptr region_begin, uptr region_end, bool is_readable) { uptr intersection_begin = Max(root_region.begin, region_begin); @@ -393,6 +477,24 @@ static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) { } } +static void IgnoredSuppressedCb(uptr chunk, void *arg) { + CHECK(arg); + chunk = GetUserBegin(chunk); + LsanMetadata m(chunk); + if (!m.allocated() || m.tag() == kIgnored) + return; + + const InternalMmapVector &suppressed = + *static_cast *>(arg); + uptr idx = InternalLowerBound(suppressed, m.stack_trace_id()); + if (idx >= suppressed.size() || m.stack_trace_id() != suppressed[idx]) + return; + + LOG_POINTERS("Suppressed: chunk %p-%p of size %zu.\n", chunk, + chunk + m.requested_size(), m.requested_size()); + m.set_tag(kIgnored); +} + // ForEachChunk callback. If chunk is marked as ignored, adds its address to // frontier. static void CollectIgnoredCb(uptr chunk, void *arg) { @@ -476,25 +578,29 @@ void ProcessPC(Frontier *frontier) { } // Sets the appropriate tag on each chunk. -static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { - // Holds the flood fill frontier. - Frontier frontier; - - ForEachChunk(CollectIgnoredCb, &frontier); - ProcessGlobalRegions(&frontier); - ProcessThreads(suspended_threads, &frontier); - ProcessRootRegions(&frontier); - FloodFillTag(&frontier, kReachable); +static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads, + Frontier *frontier) { + const InternalMmapVector &suppressed_stacks = + GetSuppressionContext()->GetSortedSuppressedStacks(); + if (!suppressed_stacks.empty()) { + ForEachChunk(IgnoredSuppressedCb, + const_cast *>(&suppressed_stacks)); + } + ForEachChunk(CollectIgnoredCb, frontier); + ProcessGlobalRegions(frontier); + ProcessThreads(suspended_threads, frontier); + ProcessRootRegions(frontier); + FloodFillTag(frontier, kReachable); - CHECK_EQ(0, frontier.size()); - ProcessPC(&frontier); + CHECK_EQ(0, frontier->size()); + ProcessPC(frontier); // The check here is relatively expensive, so we do this in a separate flood // fill. That way we can skip the check for chunks that are reachable // otherwise. LOG_POINTERS("Processing platform-specific allocations.\n"); - ProcessPlatformSpecificAllocations(&frontier); - FloodFillTag(&frontier, kReachable); + ProcessPlatformSpecificAllocations(frontier); + FloodFillTag(frontier, kReachable); // Iterate over leaked chunks and mark those that are reachable from other // leaked chunks. @@ -539,38 +645,42 @@ static void CollectLeaksCb(uptr chunk, void *arg) { } } -static void PrintMatchedSuppressions() { +void LeakSuppressionContext::PrintMatchedSuppressions() { InternalMmapVector matched; - GetSuppressionContext()->GetMatched(&matched); + context.GetMatched(&matched); if (!matched.size()) return; const char *line = "-----------------------------------------------------"; Printf("%s\n", line); Printf("Suppressions used:\n"); Printf(" count bytes template\n"); - for (uptr i = 0; i < matched.size(); i++) - Printf("%7zu %10zu %s\n", static_cast(atomic_load_relaxed( - &matched[i]->hit_count)), matched[i]->weight, matched[i]->templ); + for (uptr i = 0; i < matched.size(); i++) { + Printf("%7zu %10zu %s\n", + static_cast(atomic_load_relaxed(&matched[i]->hit_count)), + matched[i]->weight, matched[i]->templ); + } Printf("%s\n\n", line); } -struct CheckForLeaksParam { - bool success; - LeakReport leak_report; -}; - static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) { const InternalMmapVector &suspended_threads = *(const InternalMmapVector *)arg; if (tctx->status == ThreadStatusRunning) { - uptr i = InternalLowerBound(suspended_threads, 0, suspended_threads.size(), - tctx->os_id, CompareLess()); + uptr i = InternalLowerBound(suspended_threads, tctx->os_id); if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id) Report("Running thread %d was not suspended. False leaks are possible.\n", tctx->os_id); } } +#if SANITIZER_FUCHSIA + +// Fuchsia provides a libc interface that guarantees all threads are +// covered, and SuspendedThreadList is never really used. +static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {} + +#else // !SANITIZER_FUCHSIA + static void ReportUnsuspendedThreads( const SuspendedThreadsList &suspended_threads) { InternalMmapVector threads(suspended_threads.ThreadCount()); @@ -583,6 +693,8 @@ static void ReportUnsuspendedThreads( &ReportIfNotSuspended, &threads); } +#endif // !SANITIZER_FUCHSIA + static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads, void *arg) { CheckForLeaksParam *param = reinterpret_cast(arg); @@ -591,7 +703,7 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads, #if !SANITIZER_EMSCRIPTEN ReportUnsuspendedThreads(suspended_threads); #endif - ClassifyAllChunks(suspended_threads); + ClassifyAllChunks(suspended_threads, ¶m->frontier); ForEachChunk(CollectLeaksCb, ¶m->leak_report); // Clean up for subsequent leak checks. This assumes we did not overwrite any // kIgnored tags. @@ -599,44 +711,68 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads, param->success = true; } -static bool CheckForLeaks() { - if (&__lsan_is_turned_off && __lsan_is_turned_off()) - return false; - EnsureMainThreadIDIsCorrect(); - CheckForLeaksParam param; - param.success = false; - LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m); - - if (!param.success) { - Report("LeakSanitizer has encountered a fatal error.\n"); - Report( - "HINT: For debugging, try setting environment variable " - "LSAN_OPTIONS=verbosity=1:log_threads=1\n"); - Report( - "HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)\n"); - Die(); - } - param.leak_report.ApplySuppressions(); - uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount(); - if (unsuppressed_count > 0) { +static bool PrintResults(LeakReport &report) { + uptr unsuppressed_count = report.UnsuppressedLeakCount(); + if (unsuppressed_count) { Decorator d; - Printf("\n" - "=================================================================" - "\n"); + Printf( + "\n" + "=================================================================" + "\n"); Printf("%s", d.Error()); Report("ERROR: LeakSanitizer: detected memory leaks\n"); Printf("%s", d.Default()); - param.leak_report.ReportTopLeaks(flags()->max_leaks); + report.ReportTopLeaks(flags()->max_leaks); } if (common_flags()->print_suppressions) - PrintMatchedSuppressions(); + GetSuppressionContext()->PrintMatchedSuppressions(); if (unsuppressed_count > 0) { - param.leak_report.PrintSummary(); + report.PrintSummary(); return true; } return false; } +static bool CheckForLeaks() { + if (&__lsan_is_turned_off && __lsan_is_turned_off()) + return false; + // Inside LockStuffAndStopTheWorld we can't run symbolizer, so we can't match + // suppressions. However if a stack id was previously suppressed, it should be + // suppressed in future checks as well. + for (int i = 0;; ++i) { + EnsureMainThreadIDIsCorrect(); + CheckForLeaksParam param; + LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m); + if (!param.success) { + Report("LeakSanitizer has encountered a fatal error.\n"); + Report( + "HINT: For debugging, try setting environment variable " + "LSAN_OPTIONS=verbosity=1:log_threads=1\n"); + Report( + "HINT: LeakSanitizer does not work under ptrace (strace, gdb, " + "etc)\n"); + Die(); + } + // No new suppressions stacks, so rerun will not help and we can report. + if (!param.leak_report.ApplySuppressions()) + return PrintResults(param.leak_report); + + // No indirect leaks to report, so we are done here. + if (!param.leak_report.IndirectUnsuppressedLeakCount()) + return PrintResults(param.leak_report); + + if (i >= 8) { + Report("WARNING: LeakSanitizer gave up on indirect leaks suppression.\n"); + return PrintResults(param.leak_report); + } + + // We found a new previously unseen suppressed call stack. Rerun to make + // sure it does not hold indirect leaks. + VReport(1, "Rerun with %zu suppressed stacks.", + GetSuppressionContext()->GetSortedSuppressedStacks().size()); + } +} + static bool has_reported_leaks = false; bool HasReportedLeaks() { return has_reported_leaks; } @@ -657,21 +793,20 @@ static int DoRecoverableLeakCheck() { void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); } -static Suppression *GetSuppressionForAddr(uptr addr) { +Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) { Suppression *s = nullptr; // Suppress by module name. - SuppressionContext *suppressions = GetSuppressionContext(); if (const char *module_name = Symbolizer::GetOrInit()->GetModuleNameForPc(addr)) - if (suppressions->Match(module_name, kSuppressionLeak, &s)) + if (context.Match(module_name, kSuppressionLeak, &s)) return s; // Suppress by file or function name. SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr); for (SymbolizedStack *cur = frames; cur; cur = cur->next) { - if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) || - suppressions->Match(cur->info.file, kSuppressionLeak, &s)) { + if (context.Match(cur->info.function, kSuppressionLeak, &s) || + context.Match(cur->info.file, kSuppressionLeak, &s)) { break; } } @@ -679,7 +814,9 @@ static Suppression *GetSuppressionForAddr(uptr addr) { return s; } -static Suppression *GetSuppressionForStack(u32 stack_trace_id) { +Suppression *LeakSuppressionContext::GetSuppressionForStack( + u32 stack_trace_id) { + LazyInit(); StackTrace stack = StackDepotGet(stack_trace_id); for (uptr i = 0; i < stack.size; i++) { #if SANITIZER_EMSCRIPTEN @@ -691,7 +828,11 @@ static Suppression *GetSuppressionForStack(u32 stack_trace_id) { Suppression *s = GetSuppressionForAddr( StackTrace::GetPreviousInstructionPc(stack.trace[i])); #endif - if (s) return s; + if (s) { + suppressed_stacks_sorted = false; + suppressed_stacks.push_back(stack_trace_id); + return s; + } } return nullptr; } @@ -802,16 +943,21 @@ void LeakReport::PrintSummary() { ReportErrorSummary(summary.data()); } -void LeakReport::ApplySuppressions() { +uptr LeakReport::ApplySuppressions() { + LeakSuppressionContext *suppressions = GetSuppressionContext(); + uptr new_suppressions = false; for (uptr i = 0; i < leaks_.size(); i++) { - Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id); + Suppression *s = + suppressions->GetSuppressionForStack(leaks_[i].stack_trace_id); if (s) { s->weight += leaks_[i].total_size; atomic_store_relaxed(&s->hit_count, atomic_load_relaxed(&s->hit_count) + leaks_[i].hit_count); leaks_[i].is_suppressed = true; + ++new_suppressions; } } + return new_suppressions; } uptr LeakReport::UnsuppressedLeakCount() { @@ -821,6 +967,14 @@ uptr LeakReport::UnsuppressedLeakCount() { return result; } +uptr LeakReport::IndirectUnsuppressedLeakCount() { + uptr result = 0; + for (uptr i = 0; i < leaks_.size(); i++) + if (!leaks_[i].is_suppressed && !leaks_[i].is_directly_leaked) + result++; + return result; +} + } // namespace __lsan #else // CAN_SANITIZE_LEAKS namespace __lsan { @@ -923,12 +1077,11 @@ int __lsan_do_recoverable_leak_check() { return 0; } -#if !SANITIZER_SUPPORTS_WEAK_HOOKS -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -const char * __lsan_default_options() { +SANITIZER_INTERFACE_WEAK_DEF(const char *, __lsan_default_options, void) { return ""; } +#if !SANITIZER_SUPPORTS_WEAK_HOOKS SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE int __lsan_is_turned_off() { return 0; diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common.h b/system/lib/compiler-rt/lib/lsan/lsan_common.h index 6901e18829aeb..809e7e57a9f19 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_common.h +++ b/system/lib/compiler-rt/lib/lsan/lsan_common.h @@ -29,18 +29,19 @@ // To enable LeakSanitizer on a new architecture, one needs to implement the // internal_clone function as well as (probably) adjust the TLS machinery for // the new architecture inside the sanitizer library. -#if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \ - (SANITIZER_WORDSIZE == 64) && \ - (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ - defined(__powerpc64__)) +// Exclude leak-detection on arm32 for Android because `__aeabi_read_tp` +// is missing. This caused a link error. +#if SANITIZER_ANDROID && (__ANDROID_API__ < 28 || defined(__arm__)) +#define CAN_SANITIZE_LEAKS 0 +#elif (SANITIZER_LINUX || SANITIZER_MAC) && (SANITIZER_WORDSIZE == 64) && \ + (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__s390x__)) #define CAN_SANITIZE_LEAKS 1 -#elif defined(__i386__) && \ - (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) +#elif defined(__i386__) && (SANITIZER_LINUX || SANITIZER_MAC) #define CAN_SANITIZE_LEAKS 1 -#elif defined(__arm__) && \ - SANITIZER_LINUX && !SANITIZER_ANDROID +#elif defined(__arm__) && SANITIZER_LINUX #define CAN_SANITIZE_LEAKS 1 -#elif SANITIZER_EMSCRIPTEN +#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN #define CAN_SANITIZE_LEAKS 1 #else #define CAN_SANITIZE_LEAKS 0 @@ -49,6 +50,7 @@ namespace __sanitizer { class FlagParser; class ThreadRegistry; +class ThreadContextBase; struct DTLS; } @@ -102,8 +104,9 @@ class LeakReport { ChunkTag tag); void ReportTopLeaks(uptr max_leaks); void PrintSummary(); - void ApplySuppressions(); + uptr ApplySuppressions(); uptr UnsuppressedLeakCount(); + uptr IndirectUnsuppressedLeakCount(); private: void PrintReportForLeak(uptr index); @@ -126,12 +129,25 @@ struct RootRegion { uptr size; }; +// LockStuffAndStopTheWorld can start to use Scan* calls to collect into +// this Frontier vector before the StopTheWorldCallback actually runs. +// This is used when the OS has a unified callback API for suspending +// threads and enumerating roots. +struct CheckForLeaksParam { + Frontier frontier; + LeakReport leak_report; + bool success = false; +}; + InternalMmapVector const *GetRootRegions(); void ScanRootRegion(Frontier *frontier, RootRegion const ®ion, uptr region_begin, uptr region_end, bool is_readable); +void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg); +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs); // Run stoptheworld while holding any platform-specific locks, as well as the // allocator and thread registry locks. -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void* argument); +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam* argument); void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier, @@ -211,6 +227,7 @@ ThreadRegistry *GetThreadRegistryLocked(); bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls); +void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches); void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, void *arg); // Scans thread data (stacks and TLS) for heap pointers. diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp index de1efe6bc264f..a60dea00e88c8 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp @@ -102,7 +102,8 @@ void HandleLeaks() { if (common_flags()->exitcode) Die(); } -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) { +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam *argument) { // Currently, on Emscripten this does nothing and just calls the callback. // This works fine on a single-threaded environment. LockThreadRegistry(); diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common_fuchsia.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common_fuchsia.cpp new file mode 100644 index 0000000000000..2d35fa5b1cffd --- /dev/null +++ b/system/lib/compiler-rt/lib/lsan/lsan_common_fuchsia.cpp @@ -0,0 +1,165 @@ +//=-- lsan_common_fuchsia.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Implementation of common leak checking functionality. Fuchsia-specific code. +// +//===---------------------------------------------------------------------===// + +#include "lsan_common.h" +#include "sanitizer_common/sanitizer_platform.h" + +#if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA +#include + +#include "lsan_allocator.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_stoptheworld_fuchsia.h" +#include "sanitizer_common/sanitizer_thread_registry.h" + +// Ensure that the Zircon system ABI is linked in. +#pragma comment(lib, "zircon") + +namespace __lsan { + +void InitializePlatformSpecificModules() {} + +LoadedModule *GetLinker() { return nullptr; } + +__attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter; +bool DisabledInThisThread() { return disable_counter > 0; } +void DisableInThisThread() { disable_counter++; } +void EnableInThisThread() { + if (disable_counter == 0) { + DisableCounterUnderflow(); + } + disable_counter--; +} + +// There is nothing left to do after the globals callbacks. +void ProcessGlobalRegions(Frontier *frontier) {} + +// Nothing to do here. +void ProcessPlatformSpecificAllocations(Frontier *frontier) {} + +// On Fuchsia, we can intercept _Exit gracefully, and return a failing exit +// code if required at that point. Calling Die() here is undefined +// behavior and causes rare race conditions. +void HandleLeaks() {} + +int ExitHook(int status) { + return status == 0 && HasReportedLeaks() ? common_flags()->exitcode : status; +} + +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam *argument) { + LockThreadRegistry(); + LockAllocator(); + + struct Params { + InternalMmapVector allocator_caches; + StopTheWorldCallback callback; + CheckForLeaksParam *argument; + } params = {{}, callback, argument}; + + // Callback from libc for globals (data/bss modulo relro), when enabled. + auto globals = +[](void *chunk, size_t size, void *data) { + auto params = static_cast(data); + uptr begin = reinterpret_cast(chunk); + uptr end = begin + size; + ScanGlobalRange(begin, end, ¶ms->argument->frontier); + }; + + // Callback from libc for thread stacks. + auto stacks = +[](void *chunk, size_t size, void *data) { + auto params = static_cast(data); + uptr begin = reinterpret_cast(chunk); + uptr end = begin + size; + ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "STACK", + kReachable); + }; + + // Callback from libc for thread registers. + auto registers = +[](void *chunk, size_t size, void *data) { + auto params = static_cast(data); + uptr begin = reinterpret_cast(chunk); + uptr end = begin + size; + ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "REGISTERS", + kReachable); + }; + + if (flags()->use_tls) { + // Collect the allocator cache range from each thread so these + // can all be excluded from the reported TLS ranges. + GetAllThreadAllocatorCachesLocked(¶ms.allocator_caches); + __sanitizer::Sort(params.allocator_caches.data(), + params.allocator_caches.size()); + } + + // Callback from libc for TLS regions. This includes thread_local + // variables as well as C11 tss_set and POSIX pthread_setspecific. + auto tls = +[](void *chunk, size_t size, void *data) { + auto params = static_cast(data); + uptr begin = reinterpret_cast(chunk); + uptr end = begin + size; + auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin); + if (i < params->allocator_caches.size() && + params->allocator_caches[i] >= begin && + end - params->allocator_caches[i] <= sizeof(AllocatorCache)) { + // Split the range in two and omit the allocator cache within. + ScanRangeForPointers(begin, params->allocator_caches[i], + ¶ms->argument->frontier, "TLS", kReachable); + uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache); + ScanRangeForPointers(begin2, end, ¶ms->argument->frontier, "TLS", + kReachable); + } else { + ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "TLS", + kReachable); + } + }; + + // This stops the world and then makes callbacks for various memory regions. + // The final callback is the last thing before the world starts up again. + __sanitizer_memory_snapshot( + flags()->use_globals ? globals : nullptr, + flags()->use_stacks ? stacks : nullptr, + flags()->use_registers ? registers : nullptr, + flags()->use_tls ? tls : nullptr, + [](zx_status_t, void *data) { + auto params = static_cast(data); + + // We don't use the thread registry at all for enumerating the threads + // and their stacks, registers, and TLS regions. So use it separately + // just for the allocator cache, and to call ForEachExtraStackRange, + // which ASan needs. + if (flags()->use_stacks) { + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked( + [](ThreadContextBase *tctx, void *arg) { + ForEachExtraStackRange(tctx->os_id, ForEachExtraStackRangeCb, + arg); + }, + ¶ms->argument->frontier); + } + + params->callback(SuspendedThreadsListFuchsia(), params->argument); + }, + ¶ms); + + UnlockAllocator(); + UnlockThreadRegistry(); +} + +} // namespace __lsan + +// This is declared (in extern "C") by . +// _Exit calls this directly to intercept and change the status value. +int __sanitizer_process_exit_hook(int status) { + return __lsan::ExitHook(status); +} + +#endif diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common_linux.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common_linux.cpp index a9693e02edd1c..896f0479cb0a8 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_common_linux.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_common_linux.cpp @@ -93,6 +93,11 @@ static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size, return 0; } +#if SANITIZER_ANDROID && __ANDROID_API__ < 21 +extern "C" __attribute__((weak)) int dl_iterate_phdr( + int (*)(struct dl_phdr_info *, size_t, void *), void *); +#endif + // Scans global variables for heap pointers. void ProcessGlobalRegions(Frontier *frontier) { if (!flags()->use_globals) return; @@ -134,7 +139,8 @@ static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info, // while holding the libdl lock in the parent thread, we can safely reenter it // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr() // callback in the parent thread. -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) { +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam *argument) { DoStopTheWorldParam param = {callback, argument}; dl_iterate_phdr(LockStuffAndStopTheWorldCallback, ¶m); } diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common_mac.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common_mac.cpp index c1804e93c11db..8516a176eb467 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_common_mac.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_common_mac.cpp @@ -193,7 +193,8 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) { // causes rare race conditions. void HandleLeaks() {} -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) { +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam *argument) { LockThreadRegistry(); LockAllocator(); StopTheWorld(callback, argument); diff --git a/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.cpp b/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.cpp new file mode 100644 index 0000000000000..40e65c6fb7293 --- /dev/null +++ b/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.cpp @@ -0,0 +1,123 @@ +//=-- lsan_fuchsia.cpp ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Standalone LSan RTL code specific to Fuchsia. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_FUCHSIA +#include + +#include "lsan.h" +#include "lsan_allocator.h" + +using namespace __lsan; + +namespace __lsan { + +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {} + +ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {} + +struct OnCreatedArgs { + uptr stack_begin, stack_end; +}; + +// On Fuchsia, the stack bounds of a new thread are available before +// the thread itself has started running. +void ThreadContext::OnCreated(void *arg) { + // Stack bounds passed through from __sanitizer_before_thread_create_hook + // or InitializeMainThread. + auto args = reinterpret_cast(arg); + stack_begin_ = args->stack_begin; + stack_end_ = args->stack_end; +} + +struct OnStartedArgs { + uptr cache_begin, cache_end; +}; + +void ThreadContext::OnStarted(void *arg) { + auto args = reinterpret_cast(arg); + cache_begin_ = args->cache_begin; + cache_end_ = args->cache_end; +} + +void ThreadStart(u32 tid) { + OnStartedArgs args; + GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); + CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache)); + ThreadContextLsanBase::ThreadStart(tid, GetTid(), ThreadType::Regular, &args); +} + +void InitializeMainThread() { + OnCreatedArgs args; + __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end, + &args.stack_begin); + u32 tid = ThreadCreate(0, GetThreadSelf(), true, &args); + CHECK_EQ(tid, 0); + ThreadStart(tid); +} + +void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches) { + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked( + [](ThreadContextBase *tctx, void *arg) { + auto ctx = static_cast(tctx); + static_cast(arg)->push_back(ctx->cache_begin()); + }, + caches); +} + +} // namespace __lsan + +// These are declared (in extern "C") by . +// The system runtime will call our definitions directly. + +// This is called before each thread creation is attempted. So, in +// its first call, the calling thread is the initial and sole thread. +void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached, + const char *name, void *stack_base, + size_t stack_size) { + uptr user_id = reinterpret_cast(thread); + ENSURE_LSAN_INITED; + EnsureMainThreadIDIsCorrect(); + OnCreatedArgs args; + args.stack_begin = reinterpret_cast(stack_base); + args.stack_end = args.stack_begin + stack_size; + u32 parent_tid = GetCurrentThread(); + u32 tid = ThreadCreate(parent_tid, user_id, detached, &args); + return reinterpret_cast(static_cast(tid)); +} + +// This is called after creating a new thread (in the creating thread), +// with the pointer returned by __sanitizer_before_thread_create_hook (above). +void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) { + u32 tid = static_cast(reinterpret_cast(hook)); + // On success, there is nothing to do here. + if (error != thrd_success) { + // Clean up the thread registry for the thread creation that didn't happen. + GetThreadRegistryLocked()->FinishThread(tid); + } +} + +// This is called in the newly-created thread before it runs anything else, +// with the pointer returned by __sanitizer_before_thread_create_hook (above). +void __sanitizer_thread_start_hook(void *hook, thrd_t self) { + u32 tid = static_cast(reinterpret_cast(hook)); + ThreadStart(tid); +} + +// Each thread runs this just before it exits, +// with the pointer returned by BeforeThreadCreateHook (above). +// All per-thread destructors have already been called. +void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); } + +#endif // SANITIZER_FUCHSIA diff --git a/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.h b/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.h new file mode 100644 index 0000000000000..e730d8f25f21e --- /dev/null +++ b/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.h @@ -0,0 +1,35 @@ +//=-- lsan_fuchsia.h ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Standalone LSan RTL code specific to Fuchsia. +// +//===---------------------------------------------------------------------===// + +#ifndef LSAN_FUCHSIA_H +#define LSAN_FUCHSIA_H + +#include "lsan_thread.h" +#include "sanitizer_common/sanitizer_platform.h" + +#if !SANITIZER_FUCHSIA +#error "lsan_fuchsia.h is used only on Fuchsia systems (SANITIZER_FUCHSIA)" +#endif + +namespace __lsan { + +class ThreadContext final : public ThreadContextLsanBase { + public: + explicit ThreadContext(int tid); + void OnCreated(void *arg) override; + void OnStarted(void *arg) override; +}; + +} // namespace __lsan + +#endif // LSAN_FUCHSIA_H diff --git a/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp b/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp index b27f324bc558f..e90bcb50d0f3a 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -22,7 +22,9 @@ #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_platform_limits_netbsd.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" +#if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" +#endif #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "lsan.h" #include "lsan_allocator.h" @@ -61,6 +63,9 @@ INTERCEPTOR(void, free, void *p) { } INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { + // This hack is not required for Fuchsia because there are no dlsym calls + // involved in setting up interceptors. +#if !SANITIZER_FUCHSIA if (lsan_init_is_running) { // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. const uptr kCallocPoolSize = 1024; @@ -72,6 +77,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { CHECK(allocated < kCallocPoolSize); return mem; } +#endif // !SANITIZER_FUCHSIA ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; return lsan_calloc(nmemb, size, stack); @@ -100,7 +106,7 @@ INTERCEPTOR(void*, valloc, uptr size) { GET_STACK_TRACE_MALLOC; return lsan_valloc(size, stack); } -#endif +#endif // !SANITIZER_MAC #if SANITIZER_INTERCEPT_MEMALIGN INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { @@ -109,7 +115,11 @@ INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { return lsan_memalign(alignment, size, stack); } #define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) +#else +#define LSAN_MAYBE_INTERCEPT_MEMALIGN +#endif // SANITIZER_INTERCEPT_MEMALIGN +#if SANITIZER_INTERCEPT___LIBC_MEMALIGN INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; @@ -119,9 +129,8 @@ INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { } #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign) #else -#define LSAN_MAYBE_INTERCEPT_MEMALIGN #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN -#endif // SANITIZER_INTERCEPT_MEMALIGN +#endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN #if SANITIZER_INTERCEPT_ALIGNED_ALLOC INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) { @@ -307,7 +316,7 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) ///// Thread initialization and finalization. ///// -#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD +#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA static unsigned g_thread_finalize_key; static void thread_finalize(void *v) { @@ -389,6 +398,7 @@ extern "C" { int emscripten_builtin_pthread_create(void *thread, void *attr, void *(*callback)(void *), void *arg); int emscripten_builtin_pthread_join(void *th, void **ret); + int emscripten_builtin_pthread_detach(void *th); void *emscripten_builtin_malloc(size_t size); void emscripten_builtin_free(void *); } @@ -404,6 +414,8 @@ INTERCEPTOR(char *, strerror, int errnum) { #define LSAN_MAYBE_INTERCEPT_STRERROR #endif +#if SANITIZER_POSIX + struct ThreadParam { void *(*callback)(void *arg); void *param; @@ -426,7 +438,6 @@ extern "C" void *__lsan_thread_start_func(void *arg) { int tid = 0; while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) internal_sched_yield(); - SetCurrentThread(tid); ThreadStart(tid, GetTid()); #if SANITIZER_EMSCRIPTEN emscripten_builtin_free(p); @@ -498,27 +509,30 @@ INTERCEPTOR(int, pthread_join, void *th, void **ret) { return res; } +INTERCEPTOR(int, pthread_detach, void *th) { + ENSURE_LSAN_INITED; + int tid = ThreadTid((uptr)th); + int res = REAL(pthread_detach)(th); + if (res == 0) + ThreadDetach(tid); + return res; +} + #if !SANITIZER_EMSCRIPTEN INTERCEPTOR(void, _exit, int status) { if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; REAL(_exit)(status); } -#endif - -#if SANITIZER_EMSCRIPTEN -namespace __lsan { -void InitializeInterceptors() {} - -} // namespace __lsan - -#else #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) #include "sanitizer_common/sanitizer_signal_interceptors.inc" +#endif namespace __lsan { void InitializeInterceptors() { + // Fuchsia doesn't use interceptors that require any setup. +#if !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN InitializeSignalInterceptors(); INTERCEPT_FUNCTION(malloc); @@ -536,6 +550,7 @@ void InitializeInterceptors() { LSAN_MAYBE_INTERCEPT_MALLINFO; LSAN_MAYBE_INTERCEPT_MALLOPT; INTERCEPT_FUNCTION(pthread_create); + INTERCEPT_FUNCTION(pthread_detach); INTERCEPT_FUNCTION(pthread_join); INTERCEPT_FUNCTION(_exit); @@ -554,6 +569,8 @@ void InitializeInterceptors() { Die(); } #endif + +#endif // !SANITIZER_FUCHSIA } } // namespace __lsan diff --git a/system/lib/compiler-rt/lib/lsan/lsan_linux.cpp b/system/lib/compiler-rt/lib/lsan/lsan_linux.cpp index 691ce42313687..63ae2c1a945b8 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_linux.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_linux.cpp @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// // -// This file is a part of LeakSanitizer. Linux/NetBSD-specific code. +// This file is a part of LeakSanitizer. Linux/NetBSD/Fuchsia-specific code. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN +#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN #include "lsan_allocator.h" @@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {} } // namespace __lsan -#endif // SANITIZER_LINUX +#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN diff --git a/system/lib/compiler-rt/lib/lsan/lsan_posix.cpp b/system/lib/compiler-rt/lib/lsan/lsan_posix.cpp new file mode 100644 index 0000000000000..8e05915dd1b99 --- /dev/null +++ b/system/lib/compiler-rt/lib/lsan/lsan_posix.cpp @@ -0,0 +1,96 @@ +//=-- lsan_posix.cpp -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Standalone LSan RTL code common to POSIX-like systems. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_POSIX +#include "lsan.h" +#include "lsan_allocator.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_tls_get_addr.h" + +namespace __lsan { + +ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {} + +struct OnStartedArgs { + uptr stack_begin; + uptr stack_end; + uptr cache_begin; + uptr cache_end; + uptr tls_begin; + uptr tls_end; + DTLS *dtls; +}; + +void ThreadContext::OnStarted(void *arg) { + auto args = reinterpret_cast(arg); + stack_begin_ = args->stack_begin; + stack_end_ = args->stack_end; + tls_begin_ = args->tls_begin; + tls_end_ = args->tls_end; + cache_begin_ = args->cache_begin; + cache_end_ = args->cache_end; + dtls_ = args->dtls; +} + +void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) { + OnStartedArgs args; + uptr stack_size = 0; + uptr tls_size = 0; + GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size, + &args.tls_begin, &tls_size); + args.stack_end = args.stack_begin + stack_size; + args.tls_end = args.tls_begin + tls_size; + GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); + args.dtls = DTLS_Get(); + ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, &args); +} + +bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, + uptr *tls_begin, uptr *tls_end, uptr *cache_begin, + uptr *cache_end, DTLS **dtls) { + ThreadContext *context = static_cast( + GetThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id)); + if (!context) + return false; + *stack_begin = context->stack_begin(); + *stack_end = context->stack_end(); + *tls_begin = context->tls_begin(); + *tls_end = context->tls_end(); + *cache_begin = context->cache_begin(); + *cache_end = context->cache_end(); + *dtls = context->dtls(); + return true; +} + +void InitializeMainThread() { + u32 tid = ThreadCreate(0, 0, true); + CHECK_EQ(tid, 0); + ThreadStart(tid, GetTid()); +} + +static void OnStackUnwind(const SignalContext &sig, const void *, + BufferedStackTrace *stack) { + stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, + common_flags()->fast_unwind_on_fatal); +} + +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) { + HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind, + nullptr); +} + +} // namespace __lsan + +#endif // SANITIZER_POSIX diff --git a/system/lib/compiler-rt/lib/lsan/lsan_posix.h b/system/lib/compiler-rt/lib/lsan/lsan_posix.h new file mode 100644 index 0000000000000..b1265f233f363 --- /dev/null +++ b/system/lib/compiler-rt/lib/lsan/lsan_posix.h @@ -0,0 +1,49 @@ +//=-- lsan_posix.h -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Standalone LSan RTL code common to POSIX-like systems. +// +//===---------------------------------------------------------------------===// + +#ifndef LSAN_POSIX_H +#define LSAN_POSIX_H + +#include "lsan_thread.h" +#include "sanitizer_common/sanitizer_platform.h" + +#if !SANITIZER_POSIX +#error "lsan_posix.h is used only on POSIX-like systems (SANITIZER_POSIX)" +#endif + +namespace __sanitizer { +struct DTLS; +} + +namespace __lsan { + +class ThreadContext final : public ThreadContextLsanBase { + public: + explicit ThreadContext(int tid); + void OnStarted(void *arg) override; + uptr tls_begin() { return tls_begin_; } + uptr tls_end() { return tls_end_; } + DTLS *dtls() { return dtls_; } + + private: + uptr tls_begin_ = 0; + uptr tls_end_ = 0; + DTLS *dtls_ = nullptr; +}; + +void ThreadStart(u32 tid, tid_t os_id, + ThreadType thread_type = ThreadType::Regular); + +} // namespace __lsan + +#endif // LSAN_POSIX_H diff --git a/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp b/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp index 84e7ce61b9756..371a1f29dfe0b 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp @@ -13,12 +13,13 @@ #include "lsan_thread.h" +#include "lsan.h" +#include "lsan_allocator.h" +#include "lsan_common.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_thread_registry.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" -#include "lsan_allocator.h" -#include "lsan_common.h" namespace __lsan { @@ -26,7 +27,7 @@ static ThreadRegistry *thread_registry; static ThreadContextBase *CreateThreadContext(u32 tid) { void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext"); - return new(mem) ThreadContext(tid); + return new (mem) ThreadContext(tid); } static const uptr kMaxThreads = 1 << 13; @@ -34,59 +35,26 @@ static const uptr kThreadQuarantineSize = 64; void InitializeThreadRegistry() { static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)]; - thread_registry = new(thread_registry_placeholder) - ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize); + thread_registry = new (thread_registry_placeholder) + ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize); } -ThreadContext::ThreadContext(int tid) - : ThreadContextBase(tid), - stack_begin_(0), - stack_end_(0), - cache_begin_(0), - cache_end_(0), - tls_begin_(0), - tls_end_(0), - dtls_(nullptr) {} - -struct OnStartedArgs { - uptr stack_begin, stack_end, - cache_begin, cache_end, - tls_begin, tls_end; - DTLS *dtls; -}; - -void ThreadContext::OnStarted(void *arg) { - OnStartedArgs *args = reinterpret_cast(arg); - stack_begin_ = args->stack_begin; - stack_end_ = args->stack_end; - tls_begin_ = args->tls_begin; - tls_end_ = args->tls_end; - cache_begin_ = args->cache_begin; - cache_end_ = args->cache_end; - dtls_ = args->dtls; -} +ThreadContextLsanBase::ThreadContextLsanBase(int tid) + : ThreadContextBase(tid) {} -void ThreadContext::OnFinished() { +void ThreadContextLsanBase::OnFinished() { AllocatorThreadFinish(); DTLS_Destroy(); } -u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { - return thread_registry->CreateThread(user_id, detached, parent_tid, - /* arg */ nullptr); +u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached, void *arg) { + return thread_registry->CreateThread(user_id, detached, parent_tid, arg); } -void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) { - OnStartedArgs args; - uptr stack_size = 0; - uptr tls_size = 0; - GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size, - &args.tls_begin, &tls_size); - args.stack_end = args.stack_begin + stack_size; - args.tls_end = args.tls_begin + tls_size; - GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); - args.dtls = DTLS_Get(); - thread_registry->StartThread(tid, os_id, thread_type, &args); +void ThreadContextLsanBase::ThreadStart(u32 tid, tid_t os_id, + ThreadType thread_type, void *arg) { + thread_registry->StartThread(tid, os_id, thread_type, arg); + SetCurrentThread(tid); } void ThreadFinish() { @@ -95,7 +63,8 @@ void ThreadFinish() { } ThreadContext *CurrentThreadContext() { - if (!thread_registry) return nullptr; + if (!thread_registry) + return nullptr; if (GetCurrentThread() == kInvalidTid) return nullptr; // No lock needed when getting current thread. @@ -111,12 +80,17 @@ static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { } u32 ThreadTid(uptr uid) { - return thread_registry->FindThread(FindThreadByUid, (void*)uid); + return thread_registry->FindThread(FindThreadByUid, (void *)uid); +} + +void ThreadDetach(u32 tid) { + CHECK_NE(tid, kInvalidTid); + thread_registry->DetachThread(tid, /* arg */ nullptr); } void ThreadJoin(u32 tid) { CHECK_NE(tid, kInvalidTid); - thread_registry->JoinThread(tid, /* arg */nullptr); + thread_registry->JoinThread(tid, /* arg */ nullptr); } void EnsureMainThreadIDIsCorrect() { @@ -126,37 +100,16 @@ void EnsureMainThreadIDIsCorrect() { ///// Interface to the common LSan module. ///// -bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, - uptr *tls_begin, uptr *tls_end, uptr *cache_begin, - uptr *cache_end, DTLS **dtls) { - ThreadContext *context = static_cast( - thread_registry->FindThreadContextByOsIDLocked(os_id)); - if (!context) return false; - *stack_begin = context->stack_begin(); - *stack_end = context->stack_end(); - *tls_begin = context->tls_begin(); - *tls_end = context->tls_end(); - *cache_begin = context->cache_begin(); - *cache_end = context->cache_end(); - *dtls = context->dtls(); - return true; -} - void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, - void *arg) { -} + void *arg) {} -void LockThreadRegistry() { - thread_registry->Lock(); -} +void LockThreadRegistry() { thread_registry->Lock(); } -void UnlockThreadRegistry() { - thread_registry->Unlock(); -} +void UnlockThreadRegistry() { thread_registry->Unlock(); } ThreadRegistry *GetThreadRegistryLocked() { thread_registry->CheckLocked(); return thread_registry; } -} // namespace __lsan +} // namespace __lsan diff --git a/system/lib/compiler-rt/lib/lsan/lsan_thread.h b/system/lib/compiler-rt/lib/lsan/lsan_thread.h index b869d066d9d8b..36643753d0190 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan_thread.h +++ b/system/lib/compiler-rt/lib/lsan/lsan_thread.h @@ -16,38 +16,38 @@ #include "sanitizer_common/sanitizer_thread_registry.h" -namespace __sanitizer { -struct DTLS; -} - namespace __lsan { -class ThreadContext : public ThreadContextBase { +class ThreadContextLsanBase : public ThreadContextBase { public: - explicit ThreadContext(int tid); - void OnStarted(void *arg) override; + explicit ThreadContextLsanBase(int tid); void OnFinished() override; uptr stack_begin() { return stack_begin_; } uptr stack_end() { return stack_end_; } - uptr tls_begin() { return tls_begin_; } - uptr tls_end() { return tls_end_; } uptr cache_begin() { return cache_begin_; } uptr cache_end() { return cache_end_; } - DTLS *dtls() { return dtls_; } - private: - uptr stack_begin_, stack_end_, - cache_begin_, cache_end_, - tls_begin_, tls_end_; - DTLS *dtls_; + // The argument is passed on to the subclass's OnStarted member function. + static void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type, + void *onstarted_arg); + + protected: + ~ThreadContextLsanBase() {} + uptr stack_begin_ = 0; + uptr stack_end_ = 0; + uptr cache_begin_ = 0; + uptr cache_end_ = 0; }; +// This subclass of ThreadContextLsanBase is declared in an OS-specific header. +class ThreadContext; + void InitializeThreadRegistry(); +void InitializeMainThread(); -void ThreadStart(u32 tid, tid_t os_id, - ThreadType thread_type = ThreadType::Regular); +u32 ThreadCreate(u32 tid, uptr uid, bool detached, void *arg = nullptr); void ThreadFinish(); -u32 ThreadCreate(u32 tid, uptr uid, bool detached); +void ThreadDetach(u32 tid); void ThreadJoin(u32 tid); u32 ThreadTid(uptr uid); @@ -55,6 +55,7 @@ u32 GetCurrentThread(); void SetCurrentThread(u32 tid); ThreadContext *CurrentThreadContext(); void EnsureMainThreadIDIsCorrect(); + } // namespace __lsan #endif // LSAN_THREAD_H diff --git a/system/lib/compiler-rt/lib/sanitizer_common/.clang-tidy b/system/lib/compiler-rt/lib/sanitizer_common/.clang-tidy deleted file mode 100644 index 6c71abff0d382..0000000000000 --- a/system/lib/compiler-rt/lib/sanitizer_common/.clang-tidy +++ /dev/null @@ -1,16 +0,0 @@ -Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,readability-identifier-naming' -CheckOptions: - - key: readability-identifier-naming.ClassCase - value: CamelCase - - key: readability-identifier-naming.EnumCase - value: CamelCase - - key: readability-identifier-naming.FunctionCase - value: CamelCase - - key: readability-identifier-naming.UnionCase - value: CamelCase - - key: readability-identifier-naming.GlobalConstantCase - value: CamelCase - - key: readability-identifier-naming.GlobalConstantPrefix - value: "k" - - key: readability-identifier-naming.VariableCase - value: lower_case diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp index 906d4af7f5eed..3157b35ffaf80 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp @@ -25,7 +25,7 @@ const char *PrimaryAllocatorName = "SizeClassAllocator"; const char *SecondaryAllocatorName = "LargeMmapAllocator"; // ThreadSanitizer for Go uses libc malloc/free. -#if SANITIZER_GO || defined(SANITIZER_USE_MALLOC) +#if defined(SANITIZER_USE_MALLOC) # if SANITIZER_LINUX && !SANITIZER_ANDROID extern "C" void *__libc_malloc(uptr size); # if !SANITIZER_GO @@ -137,8 +137,14 @@ static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) { #endif // SANITIZER_GO || defined(SANITIZER_USE_MALLOC) +namespace { const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull; +struct BlockHeader { + u64 magic; +}; +} // namespace + static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) { SetAllocatorOutOfMemory(); Report("FATAL: %s: internal allocator is out of memory trying to allocate " @@ -147,27 +153,28 @@ static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) { } void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) { - if (size + sizeof(u64) < size) + uptr s = size + sizeof(BlockHeader); + if (s < size) return nullptr; - void *p = RawInternalAlloc(size + sizeof(u64), cache, alignment); + BlockHeader *p = (BlockHeader *)RawInternalAlloc(s, cache, alignment); if (UNLIKELY(!p)) - ReportInternalAllocatorOutOfMemory(size + sizeof(u64)); - ((u64*)p)[0] = kBlockMagic; - return (char*)p + sizeof(u64); + ReportInternalAllocatorOutOfMemory(s); + p->magic = kBlockMagic; + return p + 1; } void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) { if (!addr) return InternalAlloc(size, cache); - if (size + sizeof(u64) < size) + uptr s = size + sizeof(BlockHeader); + if (s < size) return nullptr; - addr = (char*)addr - sizeof(u64); - size = size + sizeof(u64); - CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); - void *p = RawInternalRealloc(addr, size, cache); + BlockHeader *p = (BlockHeader *)addr - 1; + CHECK_EQ(kBlockMagic, p->magic); + p = (BlockHeader *)RawInternalRealloc(p, s, cache); if (UNLIKELY(!p)) - ReportInternalAllocatorOutOfMemory(size); - return (char*)p + sizeof(u64); + ReportInternalAllocatorOutOfMemory(s); + return p + 1; } void *InternalReallocArray(void *addr, uptr count, uptr size, @@ -198,10 +205,10 @@ void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { void InternalFree(void *addr, InternalAllocatorCache *cache) { if (!addr) return; - addr = (char*)addr - sizeof(u64); - CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); - ((u64*)addr)[0] = 0; - RawInternalFree(addr, cache); + BlockHeader *p = (BlockHeader *)addr - 1; + CHECK_EQ(kBlockMagic, p->magic); + p->magic = 0; + RawInternalFree(p, cache); } // LowLevelAllocator diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h index 23d589888d3b6..5ec47416fe0c9 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h @@ -52,14 +52,14 @@ struct NoOpMapUnmapCallback { // Callback type for iterating over chunks. typedef void (*ForEachChunkCallback)(uptr chunk, void *arg); -INLINE u32 Rand(u32 *state) { // ANSI C linear congruential PRNG. +inline u32 Rand(u32 *state) { // ANSI C linear congruential PRNG. return (*state = *state * 1103515245 + 12345) >> 16; } -INLINE u32 RandN(u32 *state, u32 n) { return Rand(state) % n; } // [0, n) +inline u32 RandN(u32 *state, u32 n) { return Rand(state) % n; } // [0, n) template -INLINE void RandomShuffle(T *a, u32 n, u32 *rand_state) { +inline void RandomShuffle(T *a, u32 n, u32 *rand_state) { if (n <= 1) return; u32 state = *rand_state; for (u32 i = n - 1; i > 0; i--) diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_checks.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_checks.h index fc426f0e74f48..1cc3992c4c9fa 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_checks.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_checks.h @@ -27,7 +27,7 @@ namespace __sanitizer { void SetErrnoToENOMEM(); // A common errno setting logic shared by almost all sanitizer allocator APIs. -INLINE void *SetErrnoOnNull(void *ptr) { +inline void *SetErrnoOnNull(void *ptr) { if (UNLIKELY(!ptr)) SetErrnoToENOMEM(); return ptr; @@ -41,7 +41,7 @@ INLINE void *SetErrnoOnNull(void *ptr) { // two and that the size is a multiple of alignment for POSIX implementation, // and a bit relaxed requirement for non-POSIX ones, that the size is a multiple // of alignment. -INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { +inline bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { #if SANITIZER_POSIX return alignment != 0 && IsPowerOfTwo(alignment) && (size & (alignment - 1)) == 0; @@ -52,13 +52,13 @@ INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) { // Checks posix_memalign() parameters, verifies that alignment is a power of two // and a multiple of sizeof(void *). -INLINE bool CheckPosixMemalignAlignment(uptr alignment) { +inline bool CheckPosixMemalignAlignment(uptr alignment) { return alignment != 0 && IsPowerOfTwo(alignment) && (alignment % sizeof(void *)) == 0; } // Returns true if calloc(size, n) call overflows on size*n calculation. -INLINE bool CheckForCallocOverflow(uptr size, uptr n) { +inline bool CheckForCallocOverflow(uptr size, uptr n) { if (!size) return false; uptr max = (uptr)-1L; @@ -67,7 +67,7 @@ INLINE bool CheckForCallocOverflow(uptr size, uptr n) { // Returns true if the size passed to pvalloc overflows when rounded to the next // multiple of page_size. -INLINE bool CheckForPvallocOverflow(uptr size, uptr page_size) { +inline bool CheckForPvallocOverflow(uptr size, uptr page_size) { return RoundUpTo(size, page_size) < size; } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h index 3b1838b3985ac..b90dabbf77692 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -153,6 +153,7 @@ class SizeClassAllocator32 { } void *GetMetaData(const void *p) { + CHECK(kMetadataSize); CHECK(PointerIsMine(p)); uptr mem = reinterpret_cast(p); uptr beg = ComputeRegionBeg(mem); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h index 90603280e7c95..0a18b0c58ef79 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -72,11 +72,15 @@ class SizeClassAllocator64 { void Init(s32 release_to_os_interval_ms) { uptr TotalSpaceSize = kSpaceSize + AdditionalSize(); if (kUsingConstantSpaceBeg) { + CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize)); CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize, PrimaryAllocatorName, kSpaceBeg)); } else { - NonConstSpaceBeg = address_range.Init(TotalSpaceSize, - PrimaryAllocatorName); + // Combined allocator expects that an 2^N allocation is always aligned to + // 2^N. For this to work, the start of the space needs to be aligned as + // high as the largest size class (which also needs to be a power of 2). + NonConstSpaceBeg = address_range.InitAligned( + TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName); CHECK_NE(NonConstSpaceBeg, ~(uptr)0); } SetReleaseToOSIntervalMs(release_to_os_interval_ms); @@ -182,13 +186,13 @@ class SizeClassAllocator64 { void *GetBlockBegin(const void *p) { uptr class_id = GetSizeClass(p); + if (class_id >= kNumClasses) return nullptr; uptr size = ClassIdToSize(class_id); if (!size) return nullptr; uptr chunk_idx = GetChunkIdx((uptr)p, size); uptr reg_beg = GetRegionBegin(p); uptr beg = chunk_idx * size; uptr next_beg = beg + size; - if (class_id >= kNumClasses) return nullptr; const RegionInfo *region = AddressSpaceView::Load(GetRegionInfo(class_id)); if (region->mapped_user >= next_beg) return reinterpret_cast(reg_beg + beg); @@ -203,6 +207,7 @@ class SizeClassAllocator64 { static uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); } void *GetMetaData(const void *p) { + CHECK(kMetadataSize); uptr class_id = GetSizeClass(p); uptr size = ClassIdToSize(class_id); uptr chunk_idx = GetChunkIdx(reinterpret_cast(p), size); @@ -220,7 +225,7 @@ class SizeClassAllocator64 { // Test-only. void TestOnlyUnmap() { - UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize()); + UnmapWithCallbackOrDie((uptr)address_range.base(), address_range.size()); } static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats, diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp index d74e08010d5de..1c6520819ef93 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp @@ -134,4 +134,12 @@ void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack) { Die(); } +void NORETURN ReportRssLimitExceeded(const StackTrace *stack) { + { + ScopedAllocatorErrorReport report("rss-limit-exceeded", stack); + Report("ERROR: %s: allocator exceeded the RSS limit\n", SanitizerToolName); + } + Die(); +} + } // namespace __sanitizer diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.h index 0653c365c1cd4..6e4e6b1354916 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.h @@ -33,6 +33,7 @@ void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment, void NORETURN ReportAllocationSizeTooBig(uptr user_size, uptr max_size, const StackTrace *stack); void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack); +void NORETURN ReportRssLimitExceeded(const StackTrace *stack); } // namespace __sanitizer diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h index 1d128f55de05a..61fb98742373a 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h @@ -18,8 +18,8 @@ // (currently, 32 bits and internal allocator). class LargeMmapAllocatorPtrArrayStatic { public: - INLINE void *Init() { return &p_[0]; } - INLINE void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); } + inline void *Init() { return &p_[0]; } + inline void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); } private: static const int kMaxNumChunks = 1 << 15; uptr p_[kMaxNumChunks]; @@ -31,14 +31,14 @@ class LargeMmapAllocatorPtrArrayStatic { // same functionality in Fuchsia case, which does not support MAP_NORESERVE. class LargeMmapAllocatorPtrArrayDynamic { public: - INLINE void *Init() { + inline void *Init() { uptr p = address_range_.Init(kMaxNumChunks * sizeof(uptr), SecondaryAllocatorName); CHECK(p); return reinterpret_cast(p); } - INLINE void EnsureSpace(uptr n) { + inline void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); DCHECK(n <= n_reserved_); if (UNLIKELY(n == n_reserved_)) { diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h index a798a0cf25d9c..46f06957228c9 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h @@ -72,12 +72,12 @@ namespace __sanitizer { // Clutter-reducing helpers. template -INLINE typename T::Type atomic_load_relaxed(const volatile T *a) { +inline typename T::Type atomic_load_relaxed(const volatile T *a) { return atomic_load(a, memory_order_relaxed); } template -INLINE void atomic_store_relaxed(volatile T *a, typename T::Type v) { +inline void atomic_store_relaxed(volatile T *a, typename T::Type v) { atomic_store(a, v, memory_order_relaxed); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h index c40461ebc3bf6..fc13ca52dda74 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h @@ -34,16 +34,16 @@ namespace __sanitizer { // See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html // for mappings of the memory model to different processors. -INLINE void atomic_signal_fence(memory_order) { +inline void atomic_signal_fence(memory_order) { __asm__ __volatile__("" ::: "memory"); } -INLINE void atomic_thread_fence(memory_order) { +inline void atomic_thread_fence(memory_order) { __sync_synchronize(); } template -INLINE typename T::Type atomic_fetch_add(volatile T *a, +inline typename T::Type atomic_fetch_add(volatile T *a, typename T::Type v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -51,7 +51,7 @@ INLINE typename T::Type atomic_fetch_add(volatile T *a, } template -INLINE typename T::Type atomic_fetch_sub(volatile T *a, +inline typename T::Type atomic_fetch_sub(volatile T *a, typename T::Type v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -59,7 +59,7 @@ INLINE typename T::Type atomic_fetch_sub(volatile T *a, } template -INLINE typename T::Type atomic_exchange(volatile T *a, +inline typename T::Type atomic_exchange(volatile T *a, typename T::Type v, memory_order mo) { DCHECK(!((uptr)a % sizeof(*a))); if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst)) @@ -71,7 +71,7 @@ INLINE typename T::Type atomic_exchange(volatile T *a, } template -INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, +inline bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, typename T::Type xchg, memory_order mo) { typedef typename T::Type Type; @@ -84,7 +84,7 @@ INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, } template -INLINE bool atomic_compare_exchange_weak(volatile T *a, +inline bool atomic_compare_exchange_weak(volatile T *a, typename T::Type *cmp, typename T::Type xchg, memory_order mo) { diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h index d369aeb9935c6..59155e9883ebe 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h @@ -37,7 +37,7 @@ static struct { } __attribute__((aligned(32))) lock = {0, {0}}; template <> -INLINE atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr, +inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type val, memory_order mo) { DCHECK(mo & @@ -55,14 +55,14 @@ INLINE atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr, } template <> -INLINE atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr, +inline atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type val, memory_order mo) { return atomic_fetch_add(ptr, -val, mo); } template <> -INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr, +inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type *cmp, atomic_uint64_t::Type xchg, memory_order mo) { @@ -87,7 +87,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr, } template <> -INLINE atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr, +inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); @@ -100,7 +100,7 @@ INLINE atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr, } template <> -INLINE void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v, +inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h index b8685a8542676..4a39889e534a0 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h @@ -17,12 +17,12 @@ namespace __sanitizer { -INLINE void proc_yield(int cnt) { +inline void proc_yield(int cnt) { __asm__ __volatile__("" ::: "memory"); } template -INLINE typename T::Type atomic_load( +inline typename T::Type atomic_load( const volatile T *a, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_consume | memory_order_acquire | memory_order_seq_cst)); @@ -50,17 +50,14 @@ INLINE typename T::Type atomic_load( __sync_synchronize(); } } else { - // 64-bit load on 32-bit platform. - // Gross, but simple and reliable. - // Assume that it is not in read-only memory. - v = __sync_fetch_and_add( - const_cast(&a->val_dont_use), 0); + __atomic_load(const_cast(&a->val_dont_use), &v, + __ATOMIC_SEQ_CST); } return v; } template -INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { +inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_release | memory_order_seq_cst)); DCHECK(!((uptr)a % sizeof(*a))); @@ -79,16 +76,7 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { __sync_synchronize(); } } else { - // 64-bit store on 32-bit platform. - // Gross, but simple and reliable. - typename T::Type cmp = a->val_dont_use; - typename T::Type cur; - for (;;) { - cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v); - if (cur == cmp || cur == v) - break; - cmp = cur; - } + __atomic_store(&a->val_dont_use, &v, __ATOMIC_SEQ_CST); } } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h index f2ce553baa7a1..51597b4927412 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h @@ -16,7 +16,7 @@ namespace __sanitizer { -INLINE void proc_yield(int cnt) { +inline void proc_yield(int cnt) { __asm__ __volatile__("" ::: "memory"); for (int i = 0; i < cnt; i++) __asm__ __volatile__("pause"); @@ -24,7 +24,7 @@ INLINE void proc_yield(int cnt) { } template -INLINE typename T::Type atomic_load( +inline typename T::Type atomic_load( const volatile T *a, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_consume | memory_order_acquire | memory_order_seq_cst)); @@ -70,7 +70,7 @@ INLINE typename T::Type atomic_load( } template -INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { +inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_release | memory_order_seq_cst)); DCHECK(!((uptr)a % sizeof(*a))); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h index 6a7c5465dcbbc..31317adcdfc99 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h @@ -54,21 +54,21 @@ extern "C" long long _InterlockedExchangeAdd64(long long volatile *Addend, namespace __sanitizer { -INLINE void atomic_signal_fence(memory_order) { +inline void atomic_signal_fence(memory_order) { _ReadWriteBarrier(); } -INLINE void atomic_thread_fence(memory_order) { +inline void atomic_thread_fence(memory_order) { _mm_mfence(); } -INLINE void proc_yield(int cnt) { +inline void proc_yield(int cnt) { for (int i = 0; i < cnt; i++) _mm_pause(); } template -INLINE typename T::Type atomic_load( +inline typename T::Type atomic_load( const volatile T *a, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_consume | memory_order_acquire | memory_order_seq_cst)); @@ -86,7 +86,7 @@ INLINE typename T::Type atomic_load( } template -INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { +inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { DCHECK(mo & (memory_order_relaxed | memory_order_release | memory_order_seq_cst)); DCHECK(!((uptr)a % sizeof(*a))); @@ -102,7 +102,7 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { atomic_thread_fence(memory_order_seq_cst); } -INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a, +inline u32 atomic_fetch_add(volatile atomic_uint32_t *a, u32 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -110,7 +110,7 @@ INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a, (long)v); } -INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a, +inline uptr atomic_fetch_add(volatile atomic_uintptr_t *a, uptr v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -123,7 +123,7 @@ INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a, #endif } -INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a, +inline u32 atomic_fetch_sub(volatile atomic_uint32_t *a, u32 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -131,7 +131,7 @@ INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a, -(long)v); } -INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, +inline uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, uptr v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); @@ -144,28 +144,28 @@ INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, #endif } -INLINE u8 atomic_exchange(volatile atomic_uint8_t *a, +inline u8 atomic_exchange(volatile atomic_uint8_t *a, u8 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); return (u8)_InterlockedExchange8((volatile char*)&a->val_dont_use, v); } -INLINE u16 atomic_exchange(volatile atomic_uint16_t *a, +inline u16 atomic_exchange(volatile atomic_uint16_t *a, u16 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); return (u16)_InterlockedExchange16((volatile short*)&a->val_dont_use, v); } -INLINE u32 atomic_exchange(volatile atomic_uint32_t *a, +inline u32 atomic_exchange(volatile atomic_uint32_t *a, u32 v, memory_order mo) { (void)mo; DCHECK(!((uptr)a % sizeof(*a))); return (u32)_InterlockedExchange((volatile long*)&a->val_dont_use, v); } -INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a, +inline bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a, u8 *cmp, u8 xchgv, memory_order mo) { @@ -191,7 +191,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a, return false; } -INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a, +inline bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a, uptr *cmp, uptr xchg, memory_order mo) { @@ -204,7 +204,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a, return false; } -INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a, +inline bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a, u16 *cmp, u16 xchg, memory_order mo) { @@ -217,7 +217,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a, return false; } -INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a, +inline bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a, u32 *cmp, u32 xchg, memory_order mo) { @@ -230,7 +230,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a, return false; } -INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a, +inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a, u64 *cmp, u64 xchg, memory_order mo) { @@ -244,7 +244,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a, } template -INLINE bool atomic_compare_exchange_weak(volatile T *a, +inline bool atomic_compare_exchange_weak(volatile T *a, typename T::Type *cmp, typename T::Type xchg, memory_order mo) { diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp index f5f9f49d8cffc..87efda5bd3721 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp @@ -274,6 +274,7 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { return name_len; } +#if !SANITIZER_GO void PrintCmdline() { char **argv = GetArgv(); if (!argv) return; @@ -282,6 +283,7 @@ void PrintCmdline() { Printf("%s ", argv[i]); Printf("\n\n"); } +#endif // Malloc hooks. static const int kMaxMallocFreeHooks = 5; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h index 3b52172c483c7..a6532eee164d8 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -53,25 +53,25 @@ const u64 kExternalPCBit = 1ULL << 60; extern const char *SanitizerToolName; // Can be changed by the tool. extern atomic_uint32_t current_verbosity; -INLINE void SetVerbosity(int verbosity) { +inline void SetVerbosity(int verbosity) { atomic_store(¤t_verbosity, verbosity, memory_order_relaxed); } -INLINE int Verbosity() { +inline int Verbosity() { return atomic_load(¤t_verbosity, memory_order_relaxed); } #if SANITIZER_ANDROID -INLINE uptr GetPageSize() { +inline uptr GetPageSize() { // Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array. return 4096; } -INLINE uptr GetPageSizeCached() { +inline uptr GetPageSizeCached() { return 4096; } #else uptr GetPageSize(); extern uptr PageSizeCached; -INLINE uptr GetPageSizeCached() { +inline uptr GetPageSizeCached() { if (!PageSizeCached) PageSizeCached = GetPageSize(); return PageSizeCached; @@ -91,7 +91,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, // Memory management void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false); -INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) { +inline void *MmapOrDieQuietly(uptr size, const char *mem_type) { return MmapOrDie(size, mem_type, /*raw_report*/ true); } void UnmapOrDie(void *addr, uptr size); @@ -121,6 +121,31 @@ bool MprotectReadOnly(uptr addr, uptr size); void MprotectMallocZones(void *addr, int prot); +#if SANITIZER_LINUX +// Unmap memory. Currently only used on Linux. +void UnmapFromTo(uptr from, uptr to); +#endif + +// Maps shadow_size_bytes of shadow memory and returns shadow address. It will +// be aligned to the mmap granularity * 2^shadow_scale, or to +// 2^min_shadow_base_alignment if that is larger. The returned address will +// have max(2^min_shadow_base_alignment, mmap granularity) on the left, and +// shadow_size_bytes bytes on the right, which on linux is mapped no access. +// The high_mem_end may be updated if the original shadow size doesn't fit. +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, uptr &high_mem_end); + +// Reserve memory range [beg, end]. If madvise_shadow is true then apply +// madvise (e.g. hugepages, core dumping) requested by options. +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name, + bool madvise_shadow = true); + +// Protect size bytes of memory starting at addr. Also try to protect +// several pages at the start of the address space as specified by +// zero_base_shadow_start, at most up to the size or zero_base_max_shadow_start. +void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start, + uptr zero_base_max_shadow_start); + // Find an available address space. uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, uptr *largest_gap_found, uptr *max_occupied_addr); @@ -143,6 +168,7 @@ void RunFreeHooks(const void *ptr); class ReservedAddressRange { public: uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0); + uptr InitAligned(uptr size, uptr align, const char *name = nullptr); uptr Map(uptr fixed_addr, uptr size, const char *name = nullptr); uptr MapOrDie(uptr fixed_addr, uptr size, const char *name = nullptr); void Unmap(uptr addr, uptr size); @@ -228,7 +254,6 @@ void UpdateProcessName(); void CacheBinaryName(); void DisableCoreDumperIfNecessary(); void DumpProcessMap(); -void PrintModuleMap(); const char *GetEnv(const char *name); bool SetEnv(const char *name, const char *value); @@ -348,7 +373,7 @@ unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); } #endif -INLINE uptr MostSignificantSetBitIndex(uptr x) { +inline uptr MostSignificantSetBitIndex(uptr x) { CHECK_NE(x, 0U); unsigned long up; #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) @@ -365,7 +390,7 @@ INLINE uptr MostSignificantSetBitIndex(uptr x) { return up; } -INLINE uptr LeastSignificantSetBitIndex(uptr x) { +inline uptr LeastSignificantSetBitIndex(uptr x) { CHECK_NE(x, 0U); unsigned long up; #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) @@ -382,11 +407,11 @@ INLINE uptr LeastSignificantSetBitIndex(uptr x) { return up; } -INLINE bool IsPowerOfTwo(uptr x) { +inline bool IsPowerOfTwo(uptr x) { return (x & (x - 1)) == 0; } -INLINE uptr RoundUpToPowerOfTwo(uptr size) { +inline uptr RoundUpToPowerOfTwo(uptr size) { CHECK(size); if (IsPowerOfTwo(size)) return size; @@ -396,20 +421,20 @@ INLINE uptr RoundUpToPowerOfTwo(uptr size) { return 1ULL << (up + 1); } -INLINE uptr RoundUpTo(uptr size, uptr boundary) { +inline uptr RoundUpTo(uptr size, uptr boundary) { RAW_CHECK(IsPowerOfTwo(boundary)); return (size + boundary - 1) & ~(boundary - 1); } -INLINE uptr RoundDownTo(uptr x, uptr boundary) { +inline uptr RoundDownTo(uptr x, uptr boundary) { return x & ~(boundary - 1); } -INLINE bool IsAligned(uptr a, uptr alignment) { +inline bool IsAligned(uptr a, uptr alignment) { return (a & (alignment - 1)) == 0; } -INLINE uptr Log2(uptr x) { +inline uptr Log2(uptr x) { CHECK(IsPowerOfTwo(x)); return LeastSignificantSetBitIndex(x); } @@ -425,14 +450,14 @@ template void Swap(T& a, T& b) { } // Char handling -INLINE bool IsSpace(int c) { +inline bool IsSpace(int c) { return (c == ' ') || (c == '\n') || (c == '\t') || (c == '\f') || (c == '\r') || (c == '\v'); } -INLINE bool IsDigit(int c) { +inline bool IsDigit(int c) { return (c >= '0') && (c <= '9'); } -INLINE int ToLower(int c) { +inline int ToLower(int c) { return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c; } @@ -442,6 +467,7 @@ INLINE int ToLower(int c) { template class InternalMmapVectorNoCtor { public: + using value_type = T; void Initialize(uptr initial_capacity) { capacity_bytes_ = 0; size_ = 0; @@ -626,9 +652,13 @@ void Sort(T *v, uptr size, Compare comp = {}) { // Works like std::lower_bound: finds the first element that is not less // than the val. -template -uptr InternalLowerBound(const Container &v, uptr first, uptr last, - const Value &val, Compare comp) { +template > +uptr InternalLowerBound(const Container &v, + const typename Container::value_type &val, + Compare comp = {}) { + uptr first = 0; + uptr last = v.size(); while (last > first) { uptr mid = (first + last) / 2; if (comp(v[mid], val)) @@ -648,9 +678,31 @@ enum ModuleArch { kModuleArchARMV7, kModuleArchARMV7S, kModuleArchARMV7K, - kModuleArchARM64 + kModuleArchARM64, + kModuleArchRISCV64 }; +// Sorts and removes duplicates from the container. +template > +void SortAndDedup(Container &v, Compare comp = {}) { + Sort(v.data(), v.size(), comp); + uptr size = v.size(); + if (size < 2) + return; + uptr last = 0; + for (uptr i = 1; i < size; ++i) { + if (comp(v[last], v[i])) { + ++last; + if (last != i) + v[last] = v[i]; + } else { + CHECK(!comp(v[i], v[last])); + } + } + v.resize(last + 1); +} + // Opens the file 'file_name" and reads up to 'max_len' bytes. // The resulting buffer is mmaped and stored in '*buff'. // Returns true if file was successfully opened and read. @@ -692,6 +744,8 @@ inline const char *ModuleArchToString(ModuleArch arch) { return "armv7k"; case kModuleArchARM64: return "arm64"; + case kModuleArchRISCV64: + return "riscv64"; } CHECK(0 && "Invalid module arch"); return ""; @@ -814,15 +868,15 @@ void WriteToSyslog(const char *buffer); #if SANITIZER_MAC || SANITIZER_WIN_TRACE void LogFullErrorReport(const char *buffer); #else -INLINE void LogFullErrorReport(const char *buffer) {} +inline void LogFullErrorReport(const char *buffer) {} #endif #if SANITIZER_LINUX || SANITIZER_MAC void WriteOneLineToSyslog(const char *s); void LogMessageOnPrintf(const char *str); #else -INLINE void WriteOneLineToSyslog(const char *s) {} -INLINE void LogMessageOnPrintf(const char *str) {} +inline void WriteOneLineToSyslog(const char *s) {} +inline void LogMessageOnPrintf(const char *str) {} #endif #if SANITIZER_LINUX || SANITIZER_WIN_TRACE @@ -830,21 +884,21 @@ INLINE void LogMessageOnPrintf(const char *str) {} void AndroidLogInit(); void SetAbortMessage(const char *); #else -INLINE void AndroidLogInit() {} +inline void AndroidLogInit() {} // FIXME: MacOS implementation could use CRSetCrashLogMessage. -INLINE void SetAbortMessage(const char *) {} +inline void SetAbortMessage(const char *) {} #endif #if SANITIZER_ANDROID void SanitizerInitializeUnwinder(); AndroidApiLevel AndroidGetApiLevel(); #else -INLINE void AndroidLogWrite(const char *buffer_unused) {} -INLINE void SanitizerInitializeUnwinder() {} -INLINE AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; } +inline void AndroidLogWrite(const char *buffer_unused) {} +inline void SanitizerInitializeUnwinder() {} +inline AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; } #endif -INLINE uptr GetPthreadDestructorIterations() { +inline uptr GetPthreadDestructorIterations() { #if SANITIZER_ANDROID return (AndroidGetApiLevel() == ANDROID_LOLLIPOP_MR1) ? 8 : 4; #elif SANITIZER_POSIX @@ -855,7 +909,7 @@ INLINE uptr GetPthreadDestructorIterations() { #endif } -void *internal_start_thread(void(*func)(void*), void *arg); +void *internal_start_thread(void *(*func)(void*), void *arg); void internal_join_thread(void *th); void MaybeStartBackgroudThread(); @@ -950,7 +1004,7 @@ RunOnDestruction at_scope_exit(Fn fn) { #if SANITIZER_LINUX && SANITIZER_S390_64 void AvoidCVE_2016_2143(); #else -INLINE void AvoidCVE_2016_2143() {} +inline void AvoidCVE_2016_2143() {} #endif struct StackDepotStats { @@ -971,12 +1025,26 @@ bool GetRandom(void *buffer, uptr length, bool blocking = true); // Returns the number of logical processors on the system. u32 GetNumberOfCPUs(); extern u32 NumberOfCPUsCached; -INLINE u32 GetNumberOfCPUsCached() { +inline u32 GetNumberOfCPUsCached() { if (!NumberOfCPUsCached) NumberOfCPUsCached = GetNumberOfCPUs(); return NumberOfCPUsCached; } +template +class ArrayRef { + public: + ArrayRef() {} + ArrayRef(T *begin, T *end) : begin_(begin), end_(end) {} + + T *begin() { return begin_; } + T *end() { return end_; } + + private: + T *begin_ = nullptr; + T *end_ = nullptr; +}; + } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 2a4ab7e67a5ce..d4b9ea5f7f067 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -113,6 +113,7 @@ #define setitimer __setitimer50 #define setlocale __setlocale50 #define shmctl __shmctl50 +#define sigaltstack __sigaltstack14 #define sigemptyset __sigemptyset14 #define sigfillset __sigfillset14 #define sigpending __sigpending14 @@ -133,11 +134,7 @@ extern const short *_tolower_tab_; // Platform-specific options. #if SANITIZER_MAC -namespace __sanitizer { -bool PlatformHasDifferentMemcpyAndMemmove(); -} -#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \ - (__sanitizer::PlatformHasDifferentMemcpyAndMemmove()) +#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false #elif SANITIZER_WINDOWS64 #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false #else @@ -448,8 +445,10 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { c2 = (unsigned char)s2[i]; if (c1 != c2 || c1 == '\0') break; } - COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1); - COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1); + if (common_flags()->intercept_strcmp) { + COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1); + COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1); + } int result = CharCmpX(c1, c2); CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1, s2, result); @@ -1865,7 +1864,7 @@ UNUSED static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_gecos, REAL(strlen)(pwd->pw_gecos) + 1); #endif -#if SANITIZER_MAC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD +#if SANITIZER_MAC || SANITIZER_FREEBSD || SANITIZER_NETBSD if (pwd->pw_class) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_class, REAL(strlen)(pwd->pw_class) + 1); @@ -2202,6 +2201,24 @@ INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) { #define INIT_CLOCK_GETTIME #endif +#if SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID +INTERCEPTOR(int, clock_getcpuclockid, pid_t pid, + __sanitizer_clockid_t *clockid) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, clock_getcpuclockid, pid, clockid); + int res = REAL(clock_getcpuclockid)(pid, clockid); + if (!res && clockid) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, clockid, sizeof *clockid); + } + return res; +} + +#define INIT_CLOCK_GETCPUCLOCKID \ + COMMON_INTERCEPT_FUNCTION(clock_getcpuclockid); +#else +#define INIT_CLOCK_GETCPUCLOCKID +#endif + #if SANITIZER_INTERCEPT_GETITIMER INTERCEPTOR(int, getitimer, int which, void *curr_value) { void *ctx; @@ -3095,6 +3112,34 @@ INTERCEPTOR(int, sendmmsg, int fd, struct __sanitizer_mmsghdr *msgvec, #define INIT_SENDMMSG #endif +#if SANITIZER_INTERCEPT_SYSMSG +INTERCEPTOR(int, msgsnd, int msqid, const void *msgp, SIZE_T msgsz, + int msgflg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, msgsnd, msqid, msgp, msgsz, msgflg); + if (msgp) + COMMON_INTERCEPTOR_READ_RANGE(ctx, msgp, sizeof(long) + msgsz); + int res = REAL(msgsnd)(msqid, msgp, msgsz, msgflg); + return res; +} + +INTERCEPTOR(SSIZE_T, msgrcv, int msqid, void *msgp, SIZE_T msgsz, + long msgtyp, int msgflg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, msgrcv, msqid, msgp, msgsz, msgtyp, msgflg); + SSIZE_T len = REAL(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg); + if (len != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msgp, sizeof(long) + len); + return len; +} + +#define INIT_SYSMSG \ + COMMON_INTERCEPT_FUNCTION(msgsnd); \ + COMMON_INTERCEPT_FUNCTION(msgrcv); +#else +#define INIT_SYSMSG +#endif + #if SANITIZER_INTERCEPT_GETPEERNAME INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) { void *ctx; @@ -3705,7 +3750,7 @@ INTERCEPTOR(char *, strerror, int errnum) { // static storage. #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || \ SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD || \ - SANITIZER_FREEBSD || SANITIZER_OPENBSD + SANITIZER_FREEBSD // POSIX version. Spec is not clear on whether buf is NULL-terminated. // At least on OSX, buf contents are valid even when the call fails. INTERCEPTOR(int, strerror_r, int errnum, char *buf, SIZE_T buflen) { @@ -4042,6 +4087,41 @@ INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) { #define INIT_SIGSETOPS #endif +#if SANITIZER_INTERCEPT_SIGSET_LOGICOPS +INTERCEPTOR(int, sigandset, __sanitizer_sigset_t *dst, + __sanitizer_sigset_t *src1, __sanitizer_sigset_t *src2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigandset, dst, src1, src2); + if (src1) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src1, sizeof(*src1)); + if (src2) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src2, sizeof(*src2)); + int res = REAL(sigandset)(dst, src1, src2); + if (!res && dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); + return res; +} + +INTERCEPTOR(int, sigorset, __sanitizer_sigset_t *dst, + __sanitizer_sigset_t *src1, __sanitizer_sigset_t *src2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigorset, dst, src1, src2); + if (src1) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src1, sizeof(*src1)); + if (src2) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src2, sizeof(*src2)); + int res = REAL(sigorset)(dst, src1, src2); + if (!res && dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst)); + return res; +} +#define INIT_SIGSET_LOGICOPS \ + COMMON_INTERCEPT_FUNCTION(sigandset); \ + COMMON_INTERCEPT_FUNCTION(sigorset); +#else +#define INIT_SIGSET_LOGICOPS +#endif + #if SANITIZER_INTERCEPT_SIGPENDING INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) { void *ctx; @@ -4795,6 +4875,34 @@ INTERCEPTOR(char *, tmpnam_r, char *s) { #define INIT_TMPNAM_R #endif +#if SANITIZER_INTERCEPT_PTSNAME +INTERCEPTOR(char *, ptsname, int fd) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ptsname, fd); + char *res = REAL(ptsname)(fd); + if (res != nullptr) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); + return res; +} +#define INIT_PTSNAME COMMON_INTERCEPT_FUNCTION(ptsname); +#else +#define INIT_PTSNAME +#endif + +#if SANITIZER_INTERCEPT_PTSNAME_R +INTERCEPTOR(int, ptsname_r, int fd, char *name, SIZE_T namesize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ptsname_r, fd, name, namesize); + int res = REAL(ptsname_r)(fd, name, namesize); + if (res == 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, REAL(strlen)(name) + 1); + return res; +} +#define INIT_PTSNAME_R COMMON_INTERCEPT_FUNCTION(ptsname_r); +#else +#define INIT_PTSNAME_R +#endif + #if SANITIZER_INTERCEPT_TTYNAME INTERCEPTOR(char *, ttyname, int fd) { void *ctx; @@ -5766,6 +5874,79 @@ INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p, #define INIT_XDR #endif // SANITIZER_INTERCEPT_XDR +#if SANITIZER_INTERCEPT_XDRREC +typedef int (*xdrrec_cb)(char*, char*, int); +struct XdrRecWrapper { + char *handle; + xdrrec_cb rd, wr; +}; +typedef AddrHashMap XdrRecWrapMap; +static XdrRecWrapMap *xdrrec_wrap_map; + +static int xdrrec_wr_wrap(char *handle, char *buf, int count) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(buf, count); + XdrRecWrapper *wrap = (XdrRecWrapper *)handle; + return wrap->wr(wrap->handle, buf, count); +} + +static int xdrrec_rd_wrap(char *handle, char *buf, int count) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + XdrRecWrapper *wrap = (XdrRecWrapper *)handle; + return wrap->rd(wrap->handle, buf, count); +} + +// This doesn't apply to the solaris version as it has a different function +// signature. +INTERCEPTOR(void, xdrrec_create, __sanitizer_XDR *xdr, unsigned sndsize, + unsigned rcvsize, char *handle, int (*rd)(char*, char*, int), + int (*wr)(char*, char*, int)) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdrrec_create, xdr, sndsize, rcvsize, + handle, rd, wr); + COMMON_INTERCEPTOR_READ_RANGE(ctx, &xdr->x_op, sizeof xdr->x_op); + + // We can't allocate a wrapper on the stack, as the handle is used outside + // this stack frame. So we put it on the heap, and keep track of it with + // the HashMap (keyed by x_private). When we later need to xdr_destroy, + // we can index the map, free the wrapper, and then clean the map entry. + XdrRecWrapper *wrap_data = + (XdrRecWrapper *)InternalAlloc(sizeof(XdrRecWrapper)); + wrap_data->handle = handle; + wrap_data->rd = rd; + wrap_data->wr = wr; + if (wr) + wr = xdrrec_wr_wrap; + if (rd) + rd = xdrrec_rd_wrap; + handle = (char *)wrap_data; + + REAL(xdrrec_create)(xdr, sndsize, rcvsize, handle, rd, wr); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdr, sizeof *xdr); + + XdrRecWrapMap::Handle wrap(xdrrec_wrap_map, xdr->x_private, false, true); + *wrap = wrap_data; +} + +// We have to intercept this to be able to free wrapper memory; +// otherwise it's not necessary. +INTERCEPTOR(void, xdr_destroy, __sanitizer_XDR *xdr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdr_destroy, xdr); + + XdrRecWrapMap::Handle wrap(xdrrec_wrap_map, xdr->x_private, true); + InternalFree(*wrap); + REAL(xdr_destroy)(xdr); +} +#define INIT_XDRREC_LINUX \ + static u64 xdrrec_wrap_mem[sizeof(XdrRecWrapMap) / sizeof(u64) + 1]; \ + xdrrec_wrap_map = new ((void *)&xdrrec_wrap_mem) XdrRecWrapMap(); \ + COMMON_INTERCEPT_FUNCTION(xdrrec_create); \ + COMMON_INTERCEPT_FUNCTION(xdr_destroy); +#else +#define INIT_XDRREC_LINUX +#endif + #if SANITIZER_INTERCEPT_TSEARCH INTERCEPTOR(void *, tsearch, void *key, void **rootp, int (*compar)(const void *, const void *)) { @@ -5797,6 +5978,9 @@ void unpoison_file(__sanitizer_FILE *fp) { if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end) COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base, fp->_IO_read_end - fp->_IO_read_base); + if (fp->_IO_write_base && fp->_IO_write_base < fp->_IO_write_end) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_write_base, + fp->_IO_write_end - fp->_IO_write_base); #endif #endif // SANITIZER_HAS_STRUCT_FILE } @@ -6023,6 +6207,8 @@ INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) { INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp); + if (fp) + unpoison_file(fp); int res = REAL(fflush)(fp); // FIXME: handle fp == NULL if (fp) { @@ -6042,6 +6228,8 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) { COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp); COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); const FileMetadata *m = GetInterceptorMetadata(fp); + if (fp) + unpoison_file(fp); int res = REAL(fclose)(fp); if (m) { COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); @@ -6432,12 +6620,11 @@ INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags, if (srcaddr) srcaddr_sz = *addrlen; (void)srcaddr_sz; // prevent "set but not used" warning SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen); - if (res > 0) { + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len)); - if (srcaddr) - COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr, - Min((SIZE_T)*addrlen, srcaddr_sz)); - } + if (res >= 0 && srcaddr) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr, + Min((SIZE_T)*addrlen, srcaddr_sz)); return res; } #define INIT_RECV_RECVFROM \ @@ -7275,23 +7462,26 @@ INTERCEPTOR(int, setttyentpath, char *path) { #endif #if SANITIZER_INTERCEPT_PROTOENT -INTERCEPTOR(struct __sanitizer_protoent *, getprotoent) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, getprotoent); - struct __sanitizer_protoent *p = REAL(getprotoent)(); - if (p) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); +static void write_protoent(void *ctx, struct __sanitizer_protoent *p) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); - SIZE_T pp_size = 1; // One handles the trailing \0 + SIZE_T pp_size = 1; // One handles the trailing \0 - for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); + for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, - pp_size * sizeof(char **)); - } + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, + pp_size * sizeof(char **)); +} + +INTERCEPTOR(struct __sanitizer_protoent *, getprotoent) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotoent); + struct __sanitizer_protoent *p = REAL(getprotoent)(); + if (p) + write_protoent(ctx, p); return p; } @@ -7301,19 +7491,8 @@ INTERCEPTOR(struct __sanitizer_protoent *, getprotobyname, const char *name) { if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); struct __sanitizer_protoent *p = REAL(getprotobyname)(name); - if (p) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); - - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); - - SIZE_T pp_size = 1; // One handles the trailing \0 - - for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); - - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, - pp_size * sizeof(char **)); - } + if (p) + write_protoent(ctx, p); return p; } @@ -7321,19 +7500,8 @@ INTERCEPTOR(struct __sanitizer_protoent *, getprotobynumber, int proto) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber, proto); struct __sanitizer_protoent *p = REAL(getprotobynumber)(proto); - if (p) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); - - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1); - - SIZE_T pp_size = 1; // One handles the trailing \0 - - for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1); - - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, - pp_size * sizeof(char **)); - } + if (p) + write_protoent(ctx, p); return p; } #define INIT_PROTOENT \ @@ -7344,6 +7512,58 @@ INTERCEPTOR(struct __sanitizer_protoent *, getprotobynumber, int proto) { #define INIT_PROTOENT #endif +#if SANITIZER_INTERCEPT_PROTOENT_R +INTERCEPTOR(int, getprotoent_r, struct __sanitizer_protoent *result_buf, + char *buf, SIZE_T buflen, struct __sanitizer_protoent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotoent_r, result_buf, buf, buflen, + result); + int res = REAL(getprotoent_r)(result_buf, buf, buflen, result); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); + if (!res && *result) + write_protoent(ctx, *result); + return res; +} + +INTERCEPTOR(int, getprotobyname_r, const char *name, + struct __sanitizer_protoent *result_buf, char *buf, SIZE_T buflen, + struct __sanitizer_protoent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotobyname_r, name, result_buf, buf, + buflen, result); + if (name) + COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); + int res = REAL(getprotobyname_r)(name, result_buf, buf, buflen, result); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); + if (!res && *result) + write_protoent(ctx, *result); + return res; +} + +INTERCEPTOR(int, getprotobynumber_r, int num, + struct __sanitizer_protoent *result_buf, char *buf, + SIZE_T buflen, struct __sanitizer_protoent **result) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber_r, num, result_buf, buf, + buflen, result); + int res = REAL(getprotobynumber_r)(num, result_buf, buf, buflen, result); + + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result); + if (!res && *result) + write_protoent(ctx, *result); + return res; +} + +#define INIT_PROTOENT_R \ + COMMON_INTERCEPT_FUNCTION(getprotoent_r); \ + COMMON_INTERCEPT_FUNCTION(getprotobyname_r); \ + COMMON_INTERCEPT_FUNCTION(getprotobynumber_r); +#else +#define INIT_PROTOENT_R +#endif + #if SANITIZER_INTERCEPT_NETENT INTERCEPTOR(struct __sanitizer_netent *, getnetent) { void *ctx; @@ -9680,12 +9900,25 @@ INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size, } } qsort_compar_f old_compar = qsort_compar; - qsort_compar = compar; SIZE_T old_size = qsort_size; - qsort_size = size; + // Handle qsort() implementations that recurse using an + // interposable function call: + bool already_wrapped = compar == wrapped_qsort_compar; + if (already_wrapped) { + // This case should only happen if the qsort() implementation calls itself + // using a preemptible function call (e.g. the FreeBSD libc version). + // Check that the size and comparator arguments are as expected. + CHECK_NE(compar, qsort_compar); + CHECK_EQ(qsort_size, size); + } else { + qsort_compar = compar; + qsort_size = size; + } REAL(qsort)(base, nmemb, size, wrapped_qsort_compar); - qsort_compar = old_compar; - qsort_size = old_size; + if (!already_wrapped) { + qsort_compar = old_compar; + qsort_size = old_size; + } COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size); } #define INIT_QSORT COMMON_INTERCEPT_FUNCTION(qsort) @@ -9718,12 +9951,25 @@ INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size, } } qsort_r_compar_f old_compar = qsort_r_compar; - qsort_r_compar = compar; SIZE_T old_size = qsort_r_size; - qsort_r_size = size; + // Handle qsort_r() implementations that recurse using an + // interposable function call: + bool already_wrapped = compar == wrapped_qsort_r_compar; + if (already_wrapped) { + // This case should only happen if the qsort() implementation calls itself + // using a preemptible function call (e.g. the FreeBSD libc version). + // Check that the size and comparator arguments are as expected. + CHECK_NE(compar, qsort_r_compar); + CHECK_EQ(qsort_r_size, size); + } else { + qsort_r_compar = compar; + qsort_r_size = size; + } REAL(qsort_r)(base, nmemb, size, wrapped_qsort_r_compar, arg); - qsort_r_compar = old_compar; - qsort_r_size = old_size; + if (!already_wrapped) { + qsort_r_compar = old_compar; + qsort_r_size = old_size; + } COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size); } #define INIT_QSORT_R COMMON_INTERCEPT_FUNCTION(qsort_r) @@ -9731,6 +9977,59 @@ INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size, #define INIT_QSORT_R #endif +#if SANITIZER_INTERCEPT_SIGALTSTACK +INTERCEPTOR(int, sigaltstack, void *ss, void *oss) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigaltstack, ss, oss); + int r = REAL(sigaltstack)(ss, oss); + if (r == 0 && oss != nullptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oss, struct_stack_t_sz); + } + return r; +} +#define INIT_SIGALTSTACK COMMON_INTERCEPT_FUNCTION(sigaltstack) +#else +#define INIT_SIGALTSTACK +#endif + +#if SANITIZER_INTERCEPT_UNAME +INTERCEPTOR(int, uname, struct utsname *utsname) { +#if SANITIZER_LINUX + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_uname(utsname); +#endif + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, uname, utsname); + int res = REAL(uname)(utsname); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, + __sanitizer::struct_utsname_sz); + return res; +} +#define INIT_UNAME COMMON_INTERCEPT_FUNCTION(uname) +#else +#define INIT_UNAME +#endif + +#if SANITIZER_INTERCEPT___XUNAME +// FreeBSD's define uname() as +// static __inline int uname(struct utsname *name) { +// return __xuname(SYS_NMLN, (void*)name); +// } +INTERCEPTOR(int, __xuname, int size, void *utsname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __xuname, size, utsname); + int res = REAL(__xuname)(size, utsname); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, + __sanitizer::struct_utsname_sz); + return res; +} +#define INIT___XUNAME COMMON_INTERCEPT_FUNCTION(__xuname) +#else +#define INIT___XUNAME +#endif + #include "sanitizer_common_interceptors_netbsd_compat.inc" static void InitializeCommonInterceptors() { @@ -9804,6 +10103,7 @@ static void InitializeCommonInterceptors() { INIT_FGETGRENT_R; INIT_SETPWENT; INIT_CLOCK_GETTIME; + INIT_CLOCK_GETCPUCLOCKID; INIT_GETITIMER; INIT_TIME; INIT_GLOB; @@ -9830,6 +10130,7 @@ static void InitializeCommonInterceptors() { INIT_SENDMSG; INIT_RECVMMSG; INIT_SENDMMSG; + INIT_SYSMSG; INIT_GETPEERNAME; INIT_IOCTL; INIT_INET_ATON; @@ -9866,6 +10167,7 @@ static void InitializeCommonInterceptors() { INIT_SIGWAITINFO; INIT_SIGTIMEDWAIT; INIT_SIGSETOPS; + INIT_SIGSET_LOGICOPS; INIT_SIGPENDING; INIT_SIGPROCMASK; INIT_PTHREAD_SIGMASK; @@ -9907,6 +10209,8 @@ static void InitializeCommonInterceptors() { INIT_PTHREAD_BARRIERATTR_GETPSHARED; INIT_TMPNAM; INIT_TMPNAM_R; + INIT_PTSNAME; + INIT_PTSNAME_R; INIT_TTYNAME; INIT_TTYNAME_R; INIT_TEMPNAM; @@ -9936,6 +10240,7 @@ static void InitializeCommonInterceptors() { INIT_BZERO; INIT_FTIME; INIT_XDR; + INIT_XDRREC_LINUX; INIT_TSEARCH; INIT_LIBIO_INTERNALS; INIT_FOPEN; @@ -9993,6 +10298,7 @@ static void InitializeCommonInterceptors() { INIT_STRMODE; INIT_TTYENT; INIT_PROTOENT; + INIT_PROTOENT_R; INIT_NETENT; INIT_GETMNTINFO; INIT_MI_VECTOR_HASH; @@ -10036,6 +10342,9 @@ static void InitializeCommonInterceptors() { INIT_GETENTROPY; INIT_QSORT; INIT_QSORT_R; + INIT_SIGALTSTACK; + INIT_UNAME; + INIT___XUNAME; INIT___PRINTF_CHK; } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc index bbbedda8fbe21..082398ba960af 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc @@ -340,6 +340,12 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc, size = 0; } COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size); + // For %ms/%mc, write the allocated output buffer as well. + if (dir.allocate) { + char *buf = *(char **)argp; + if (buf) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, internal_strlen(buf) + 1); + } } } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc index 490a04b2181b0..7f181258eab52 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc @@ -330,13 +330,17 @@ static void ioctl_table_fill() { _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int)); _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int)); _(TCFLSH, NONE, 0); +#if SANITIZER_GLIBC _(TCGETA, WRITE, struct_termio_sz); +#endif _(TCGETS, WRITE, struct_termios_sz); _(TCSBRK, NONE, 0); _(TCSBRKP, NONE, 0); +#if SANITIZER_GLIBC _(TCSETA, READ, struct_termio_sz); _(TCSETAF, READ, struct_termio_sz); _(TCSETAW, READ, struct_termio_sz); +#endif _(TCSETS, READ, struct_termios_sz); _(TCSETSF, READ, struct_termios_sz); _(TCSETSW, READ, struct_termios_sz); @@ -364,7 +368,7 @@ static void ioctl_table_fill() { _(VT_WAITACTIVE, NONE, 0); #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID +#if SANITIZER_GLIBC // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE _(CYGETDEFTHRESH, WRITE, sizeof(int)); _(CYGETDEFTIMEOUT, WRITE, sizeof(int)); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc index c78b6e10b6895..932e5478616d5 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc @@ -13,6 +13,7 @@ INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address) INTERFACE_FUNCTION(__sanitizer_set_death_callback) INTERFACE_FUNCTION(__sanitizer_set_report_path) INTERFACE_FUNCTION(__sanitizer_set_report_fd) +INTERFACE_FUNCTION(__sanitizer_get_report_path) INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container) INTERFACE_WEAK_FUNCTION(__sanitizer_on_print) INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary) diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp index 27d6a177760e4..047c5a17ea6e7 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp @@ -30,7 +30,7 @@ SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() { return nullptr; } -void BackgroundThread(void *arg) { +void *BackgroundThread(void *arg) { const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb; const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb; const bool heap_profile = common_flags()->heap_profile; @@ -129,6 +129,69 @@ void SetSandboxingCallback(void (*f)()) { sandboxing_callback = f; } +uptr ReservedAddressRange::InitAligned(uptr size, uptr align, + const char *name) { + CHECK(IsPowerOfTwo(align)); + if (align <= GetPageSizeCached()) + return Init(size, name); + uptr start = Init(size + align, name); + start += align - (start & (align - 1)); + return start; +} + +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS + +// Reserve memory range [beg, end]. +// We need to use inclusive range because end+1 may not be representable. +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name, + bool madvise_shadow) { + CHECK_EQ((beg % GetMmapGranularity()), 0); + CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); + uptr size = end - beg + 1; + DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. + if (madvise_shadow ? !MmapFixedSuperNoReserve(beg, size, name) + : !MmapFixedNoReserve(beg, size, name)) { + Report( + "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " + "Perhaps you're using ulimit -v\n", + size); + Abort(); + } + if (madvise_shadow && common_flags()->use_madv_dontdump) + DontDumpShadowMemory(beg, size); +} + +void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start, + uptr zero_base_max_shadow_start) { + if (!size) + return; + void *res = MmapFixedNoAccess(addr, size, "shadow gap"); + if (addr == (uptr)res) + return; + // A few pages at the start of the address space can not be protected. + // But we really want to protect as much as possible, to prevent this memory + // being returned as a result of a non-FIXED mmap(). + if (addr == zero_base_shadow_start) { + uptr step = GetMmapGranularity(); + while (size > step && addr < zero_base_max_shadow_start) { + addr += step; + size -= step; + void *res = MmapFixedNoAccess(addr, size, "shadow gap"); + if (addr == (uptr)res) + return; + } + } + + Report( + "ERROR: Failed to protect the shadow gap. " + "%s cannot proceed correctly. ABORTING.\n", + SanitizerToolName); + DumpProcessMap(); + Die(); +} + +#endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS + } // namespace __sanitizer SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify, diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp index 3b278e017eb7c..487a634a16523 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp @@ -10,9 +10,10 @@ // libc in no-libcdep sources. //===----------------------------------------------------------------------===// -#include "sanitizer_platform.h" #include "sanitizer_common.h" +#include "sanitizer_flags.h" #include "sanitizer_libc.h" +#include "sanitizer_platform.h" namespace __sanitizer { @@ -29,6 +30,7 @@ void SleepForSeconds(int seconds) { internal_sleep(seconds); } #if !SANITIZER_WINDOWS && !SANITIZER_MAC void ListOfModules::init() {} +void InitializePlatformCommonFlags(CommonFlags *cf) {} #endif } // namespace __sanitizer diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc index 31ff48cfd2cfc..1b89d6e176840 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc @@ -2294,9 +2294,10 @@ PRE_SYSCALL(ni_syscall)() {} POST_SYSCALL(ni_syscall)(long res) {} PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { -#if !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__)) +#if !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \ + SANITIZER_RISCV64) if (data) { if (request == ptrace_setregs) { PRE_READ((void *)data, struct_user_regs_struct_sz); @@ -2315,9 +2316,10 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { } POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) { -#if !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__)) +#if !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \ + SANITIZER_RISCV64) if (res >= 0 && data) { // Note that this is different from the interceptor in // sanitizer_common_interceptors.inc. @@ -2885,6 +2887,23 @@ POST_SYSCALL(getrandom)(long res, void *buf, uptr count, long flags) { POST_WRITE(buf, res); } } + +PRE_SYSCALL(sigaltstack)(const void *ss, void *oss) { + if (ss != nullptr) { + PRE_READ(ss, struct_stack_t_sz); + } + if (oss != nullptr) { + PRE_WRITE(oss, struct_stack_t_sz); + } +} + +POST_SYSCALL(sigaltstack)(long res, void *ss, void *oss) { + if (res == 0) { + if (oss != nullptr) { + POST_WRITE(oss, struct_stack_t_sz); + } + } +} } // extern "C" #undef PRE_SYSCALL diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp index f18cee66b8431..a52db08433e3b 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp @@ -27,15 +27,15 @@ #include "sanitizer_platform.h" #if SANITIZER_FUCHSIA +#include +#include +#include + #include "sanitizer_atomic.h" #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" #include "sanitizer_symbolizer_fuchsia.h" -#include -#include -#include - using namespace __sanitizer; namespace __sancov { @@ -82,7 +82,8 @@ class TracePcGuardController final { void TracePcGuard(u32 *guard, uptr pc) { atomic_uint32_t *guard_ptr = reinterpret_cast(guard); u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed); - if (idx > 0) array_[idx] = pc; + if (idx > 0) + array_[idx] = pc; } void Dump() { @@ -140,6 +141,10 @@ class TracePcGuardController final { internal_getpid()); _zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_, internal_strlen(vmo_name_)); + uint64_t size = DataSize(); + status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size, + sizeof(size)); + CHECK_EQ(status, ZX_OK); // Map the largest possible view we might need into the VMO. Later // we might need to increase the VMO's size before we can use larger @@ -172,6 +177,10 @@ class TracePcGuardController final { zx_status_t status = _zx_vmo_set_size(vmo_, DataSize()); CHECK_EQ(status, ZX_OK); + uint64_t size = DataSize(); + status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size, + sizeof(size)); + CHECK_EQ(status, ZX_OK); return first_index; } @@ -204,13 +213,15 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr *pcs, } SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) { - if (!*guard) return; + if (!*guard) + return; __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); } SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *start, u32 *end) { - if (start == end || *start) return; + if (start == end || *start) + return; __sancov::pc_guard_controller.InitTracePcGuard(start, end); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc index 7beeff7e8af80..d7ab0c3d98c15 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -29,4 +29,5 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_bool_flag_init) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init) diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp index 6a75792f92624..73ebeb5fa14ad 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp @@ -207,6 +207,7 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_bool_flag_init, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} } // extern "C" // Weak definition for code instrumented with -fsanitize-coverage=stack-depth diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp index d4a325bea4b2d..2c924f5d39639 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp @@ -32,7 +32,7 @@ struct DDLogicalThread { bool report_pending; }; -struct DD : public DDetector { +struct DD final : public DDetector { SpinMutex mtx; DeadlockDetector dd; DDFlags flags; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp index 4026739d4e515..e3f8e1b127623 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp @@ -80,7 +80,7 @@ struct Mutex { Link link[kMaxLink]; }; -struct DD : public DDetector { +struct DD final : public DDetector { explicit DD(const DDFlags *flags); DDPhysicalThread* CreatePhysicalThread(); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h index a4722b080ebd1..7f461c98bade4 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h @@ -66,6 +66,9 @@ struct DDCallback { virtual u32 Unwind() { return 0; } virtual int UniqueTid() { return 0; } + + protected: + ~DDCallback() {} }; struct DDetector { @@ -85,6 +88,9 @@ struct DDetector { virtual void MutexDestroy(DDCallback *cb, DDMutex *m) {} virtual DDReport *GetReport(DDCallback *cb) { return nullptr; } + + protected: + ~DDetector() {} }; } // namespace __sanitizer diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp index 6cdfa28a95afd..785ebf97169d8 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp @@ -124,12 +124,16 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, #endif } +class SuspendedThreadsListEmscripten final : public SuspendedThreadsList {}; + void StopTheWorld(StopTheWorldCallback callback, void *argument) { // TODO: have some workable alternative, since we can't just fork and suspend // the parent process. This does not matter when single thread. - callback(SuspendedThreadsList(), argument); + callback(SuspendedThreadsListEmscripten(), argument); } +void InitializePlatformCommonFlags(CommonFlags *cf) {} + } // namespace __sanitizer #endif diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno.h index 584e66e4a861a..94f16b6e87358 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno.h @@ -23,7 +23,7 @@ #if SANITIZER_FREEBSD || SANITIZER_MAC # define __errno_location __error -#elif SANITIZER_ANDROID || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ +#elif SANITIZER_ANDROID || SANITIZER_NETBSD || \ SANITIZER_RTEMS # define __errno_location __errno #elif SANITIZER_SOLARIS diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h index 7f797c2c4c15c..650cf99128d78 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h @@ -24,9 +24,10 @@ namespace __sanitizer { -#define errno_ENOMEM __WASI_ERRNO_NOMEM -#define errno_EBUSY __WASI_ERRNO_BUSY -#define errno_EINVAL __WASI_ERRNO_INVAL +#define errno_ENOMEM __WASI_ERRNO_NOMEM +#define errno_EBUSY __WASI_ERRNO_BUSY +#define errno_EINVAL __WASI_ERRNO_INVAL +#define errno_ENAMETOOLONG __WASI_ERRNO_NAMETOOLONG // Those might not present or their value differ on different platforms. extern const int errno_EOWNERDEAD; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp index 79930d7942501..7c64b53e9b11d 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp @@ -58,40 +58,49 @@ void ReportFile::ReopenIfNecessary() { } else { internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); } - fd = OpenFile(full_path, WrOnly); + error_t err; + fd = OpenFile(full_path, WrOnly, &err); if (fd == kInvalidFd) { const char *ErrorMsgPrefix = "ERROR: Can't open file: "; WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); + char errmsg[100]; + internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)", err); + WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg)); Die(); } fd_pid = pid; } void ReportFile::SetReportPath(const char *path) { - if (!path) - return; - uptr len = internal_strlen(path); - if (len > sizeof(path_prefix) - 100) { - Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", - path[0], path[1], path[2], path[3], - path[4], path[5], path[6], path[7]); - Die(); + if (path) { + uptr len = internal_strlen(path); + if (len > sizeof(path_prefix) - 100) { + Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", path[0], path[1], + path[2], path[3], path[4], path[5], path[6], path[7]); + Die(); + } } SpinMutexLock l(mu); if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) CloseFile(fd); fd = kInvalidFd; - if (internal_strcmp(path, "stdout") == 0) { - fd = kStdoutFd; - } else if (internal_strcmp(path, "stderr") == 0) { + if (!path || internal_strcmp(path, "stderr") == 0) { fd = kStderrFd; + } else if (internal_strcmp(path, "stdout") == 0) { + fd = kStdoutFd; } else { internal_snprintf(path_prefix, kMaxPathLength, "%s", path); } } +const char *ReportFile::GetReportPath() { + SpinMutexLock l(mu); + ReopenIfNecessary(); + return full_path; +} + bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, uptr *read_len, uptr max_len, error_t *errno_p) { *buff = nullptr; @@ -210,6 +219,10 @@ void __sanitizer_set_report_fd(void *fd) { report_file.fd = (fd_t)reinterpret_cast(fd); report_file.fd_pid = internal_getpid(); } + +const char *__sanitizer_get_report_path() { + return report_file.GetReportPath(); +} } // extern "C" #endif // !SANITIZER_FUCHSIA diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h index 4a78a0e0ac881..08671ab67d0f5 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h @@ -26,6 +26,7 @@ struct ReportFile { void Write(const char *buffer, uptr length); bool SupportsColors(); void SetReportPath(const char *path); + const char *GetReportPath(); // Don't use fields directly. They are only declared public to allow // aggregate initialization. @@ -87,8 +88,8 @@ bool IsAbsolutePath(const char *path); // The child process will close all fds after STDERR_FILENO // before passing control to a program. pid_t StartSubprocess(const char *filename, const char *const argv[], - fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, - fd_t stderr_fd = kInvalidFd); + const char *const envp[], fd_t stdin_fd = kInvalidFd, + fd_t stdout_fd = kInvalidFd, fd_t stderr_fd = kInvalidFd); // Checks if specified process is still running bool IsProcessRunning(pid_t pid); // Waits for the process to finish and returns its exit code. diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h index fac5dff346333..acc71ccd89eea 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h @@ -42,7 +42,7 @@ class FlagHandlerBase { }; template -class FlagHandler : public FlagHandlerBase { +class FlagHandler final : public FlagHandlerBase { T *t_; public: diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp index 684ee1e0b9995..21048be730416 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp @@ -13,9 +13,10 @@ #include "sanitizer_flags.h" #include "sanitizer_common.h" +#include "sanitizer_flag_parser.h" #include "sanitizer_libc.h" +#include "sanitizer_linux.h" #include "sanitizer_list.h" -#include "sanitizer_flag_parser.h" namespace __sanitizer { @@ -72,7 +73,7 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) { *out = '\0'; } -class FlagHandlerInclude : public FlagHandlerBase { +class FlagHandlerInclude final : public FlagHandlerBase { FlagParser *parser_; bool ignore_missing_; const char *original_path_; @@ -91,7 +92,7 @@ class FlagHandlerInclude : public FlagHandlerBase { } return parser_->ParseFile(value, ignore_missing_); } - bool Format(char *buffer, uptr size) { + bool Format(char *buffer, uptr size) override { // Note `original_path_` isn't actually what's parsed due to `%` // substitutions. Printing the substituted path would require holding onto // mmap'ed memory. @@ -124,6 +125,8 @@ void InitializeCommonFlags(CommonFlags *cf) { // need to record coverage to generate coverage report. cf->coverage |= cf->html_cov_report; SetVerbosity(cf->verbosity); + + InitializePlatformCommonFlags(cf); } } // namespace __sanitizer diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h index 8f5e987da3ffd..5b59e5801bf91 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h @@ -62,6 +62,10 @@ void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf); // and perform initializations common to all sanitizers (e.g. setting // verbosity). void InitializeCommonFlags(CommonFlags *cf = &common_flags_dont_use); + +// Platform specific flags initialization. +void InitializePlatformCommonFlags(CommonFlags *cf); + } // namespace __sanitizer #endif // SANITIZER_FLAGS_H diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc index 065258a5a6e13..cfb5822645f13 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc @@ -40,16 +40,21 @@ COMMON_FLAG(bool, fast_unwind_on_check, false, COMMON_FLAG(bool, fast_unwind_on_fatal, false, "If available, use the fast frame-pointer-based unwinder on fatal " "errors.") -COMMON_FLAG(bool, fast_unwind_on_malloc, true, +// ARM thumb/thumb2 frame pointer is inconsistent on GCC and Clang [1] +// and fast-unwider is also unreliable with mixing arm and thumb code [2]. +// [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92172 +// [2] https://bugs.llvm.org/show_bug.cgi?id=44158 +COMMON_FLAG(bool, fast_unwind_on_malloc, + !(SANITIZER_LINUX && !SANITIZER_ANDROID && SANITIZER_ARM), "If available, use the fast frame-pointer-based unwinder on " "malloc/free.") COMMON_FLAG(bool, handle_ioctl, false, "Intercept and handle ioctl requests.") COMMON_FLAG(int, malloc_context_size, 1, "Max number of stack frames kept for each allocation/deallocation.") COMMON_FLAG( - const char *, log_path, "stderr", + const char *, log_path, nullptr, "Write logs to \"log_path.pid\". The special values are \"stdout\" and " - "\"stderr\". The default is \"stderr\".") + "\"stderr\". If unspecified, defaults to \"stderr\".") COMMON_FLAG( bool, log_exe_name, false, "Mention name of executable when reporting error and " @@ -77,8 +82,9 @@ COMMON_FLAG(bool, print_summary, true, "If false, disable printing error summaries in addition to error " "reports.") COMMON_FLAG(int, print_module_map, 0, - "OS X only (0 - don't print, 1 - print only once before process " - "exits, 2 - print after each report).") + "Print the process module map where supported (0 - don't print, " + "1 - print only once before process exits, 2 - print after each " + "report).") COMMON_FLAG(bool, check_printf, true, "Check printf arguments.") #define COMMON_FLAG_HANDLE_SIGNAL_HELP(signal) \ "Controls custom tool's " #signal " handler (0 - do not registers the " \ @@ -195,6 +201,9 @@ COMMON_FLAG(bool, intercept_strtok, true, COMMON_FLAG(bool, intercept_strpbrk, true, "If set, uses custom wrappers for strpbrk function " "to find more errors.") +COMMON_FLAG( + bool, intercept_strcmp, true, + "If set, uses custom wrappers for strcmp functions to find more errors.") COMMON_FLAG(bool, intercept_strlen, true, "If set, uses custom wrappers for strlen and strnlen functions " "to find more errors.") diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h index 64cb21f1c3d2b..82b227eab6dab 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h @@ -19,11 +19,11 @@ // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in // 32-bit mode. #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) -# include -# if __FreeBSD_version <= 902001 // v9.2 -# include -# include -# include +#include +#if __FreeBSD_version <= 902001 // v9.2 +#include +#include +#include namespace __sanitizer { @@ -68,8 +68,8 @@ typedef struct __xmcontext { } xmcontext_t; typedef struct __xucontext { - sigset_t uc_sigmask; - xmcontext_t uc_mcontext; + sigset_t uc_sigmask; + xmcontext_t uc_mcontext; struct __ucontext *uc_link; stack_t uc_stack; @@ -122,15 +122,16 @@ struct xdl_phdr_info { void *dlpi_tls_data; }; -typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info*, size_t, void*); -typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void*); +typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info *, size_t, + void *); +typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void *); #define xdl_iterate_phdr(callback, param) \ - (((xdl_iterate_phdr_t*) dl_iterate_phdr)((callback), (param))) + (((xdl_iterate_phdr_t *)dl_iterate_phdr)((callback), (param))) } // namespace __sanitizer -# endif // __FreeBSD_version <= 902001 +#endif // __FreeBSD_version <= 902001 #endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) #endif // SANITIZER_FREEBSD_H diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp index 6e2c6137f0ce7..5ad20d0d7da62 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp @@ -14,10 +14,6 @@ #include "sanitizer_fuchsia.h" #if SANITIZER_FUCHSIA -#include "sanitizer_common.h" -#include "sanitizer_libc.h" -#include "sanitizer_mutex.h" - #include #include #include @@ -25,6 +21,11 @@ #include #include #include +#include + +#include "sanitizer_common.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" namespace __sanitizer { @@ -47,8 +48,10 @@ unsigned int internal_sleep(unsigned int seconds) { } u64 NanoTime() { + zx_handle_t utc_clock = _zx_utc_reference_get(); + CHECK_NE(utc_clock, ZX_HANDLE_INVALID); zx_time_t time; - zx_status_t status = _zx_clock_get(ZX_CLOCK_UTC, &time); + zx_status_t status = _zx_clock_read(utc_clock, &time); CHECK_EQ(status, ZX_OK); return time; } @@ -66,6 +69,10 @@ uptr internal_getpid() { return pid; } +int internal_dlinfo(void *handle, int request, void *p) { + UNIMPLEMENTED(); +} + uptr GetThreadSelf() { return reinterpret_cast(thrd_current()); } tid_t GetTid() { return GetThreadSelf(); } @@ -101,8 +108,6 @@ void SetAlternateSignalStack() {} void UnsetAlternateSignalStack() {} void InitTlsSize() {} -void PrintModuleMap() {} - bool SignalContext::IsStackOverflow() const { return false; } void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); } const char *SignalContext::Describe() const { UNIMPLEMENTED(); } @@ -500,6 +505,8 @@ u32 GetNumberOfCPUs() { uptr GetRSS() { UNIMPLEMENTED(); } +void InitializePlatformCommonFlags(CommonFlags *cf) {} + } // namespace __sanitizer using namespace __sanitizer; @@ -522,6 +529,10 @@ void __sanitizer_set_report_path(const char *path) { void __sanitizer_set_report_fd(void *fd) { UNREACHABLE("not available on Fuchsia"); } + +const char *__sanitizer_get_report_path() { + UNREACHABLE("not available on Fuchsia"); +} } // extern "C" #endif // SANITIZER_FUCHSIA diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.h index 5a2ad32b4113b..96f9cde7ef191 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.h @@ -18,12 +18,18 @@ #include "sanitizer_common.h" #include +#include namespace __sanitizer { extern uptr MainThreadStackBase, MainThreadStackSize; extern sanitizer_shadow_bounds_t ShadowBounds; +struct MemoryMappingLayoutData { + InternalMmapVector data; + size_t current; // Current index into the vector. +}; + } // namespace __sanitizer #endif // SANITIZER_FUCHSIA diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h index 86ad3a5e2c2aa..38439e44f611e 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h @@ -21,8 +21,9 @@ #if SANITIZER_LINUX || SANITIZER_FUCHSIA -# if __GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \ - SANITIZER_FUCHSIA +# if (__GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \ + SANITIZER_FUCHSIA) && \ + !SANITIZER_GO # define SANITIZER_USE_GETAUXVAL 1 # else # define SANITIZER_USE_GETAUXVAL 0 diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc index d0cc4da9755f4..576807ea3a6a1 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc @@ -446,9 +446,6 @@ static void ioctl_table_fill() { _(STICIO_STOPQ, NONE, 0); /* Entries from file: dev/usb/ukyopon.h */ _(UKYOPON_IDENTIFY, WRITE, struct_ukyopon_identify_sz); - /* Entries from file: dev/usb/urio.h */ - _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz); - _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz); /* Entries from file: dev/usb/usb.h */ _(USB_REQUEST, READWRITE, struct_usb_ctl_request_sz); _(USB_SETDEBUG, READ, sizeof(int)); @@ -1405,6 +1402,9 @@ static void ioctl_table_fill() { /* Entries from file: dev/filemon/filemon.h (compat <= 9.99.26) */ _(FILEMON_SET_FD, READWRITE, sizeof(int)); _(FILEMON_SET_PID, READWRITE, sizeof(int)); + /* Entries from file: dev/usb/urio.h (compat <= 9.99.43) */ + _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz); + _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz); #undef _ } // NOLINT diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h index c110eff130f24..0b001c1c48300 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h @@ -28,6 +28,10 @@ extern "C" { // (casted to void *). SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_set_report_fd(void *fd); + // Get the current full report file path, if a path was specified by + // an earlier call to __sanitizer_set_report_path. Returns null otherwise. + SANITIZER_INTERFACE_ATTRIBUTE + const char *__sanitizer_get_report_path(); typedef struct { int coverage_sandboxed; @@ -109,8 +113,10 @@ extern "C" { __sanitizer::u32*); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_cov_8bit_counters_init(); - SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE - void __sanitizer_cov_pcs_init(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void + __sanitizer_cov_bool_flag_init(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void + __sanitizer_cov_pcs_init(); } // extern "C" #endif // SANITIZER_INTERFACE_INTERNAL_H diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h index 4e4609c27cb66..9e6f406029e0d 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h @@ -39,7 +39,7 @@ // TLS is handled differently on different platforms #if SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_FREEBSD || SANITIZER_OPENBSD + SANITIZER_FREEBSD # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \ __attribute__((tls_model("initial-exec"))) thread_local #else @@ -104,8 +104,7 @@ // // FIXME: do we have anything like this on Mac? #ifndef SANITIZER_CAN_USE_PREINIT_ARRAY -#if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_OPENBSD || \ - SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC) +#if (SANITIZER_LINUX || SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC) #define SANITIZER_CAN_USE_PREINIT_ARRAY 1 // Before Solaris 11.4, .preinit_array is fully supported only with GNU ld. // FIXME: Check for those conditions. @@ -170,7 +169,7 @@ typedef int pid_t; #endif #if SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_MAC || \ + SANITIZER_MAC || \ (SANITIZER_SOLARIS && (defined(_LP64) || _FILE_OFFSET_BITS == 64)) || \ (SANITIZER_LINUX && defined(__x86_64__)) typedef u64 OFF_T; @@ -182,8 +181,7 @@ typedef u64 OFF64_T; #if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC typedef uptr operator_new_size_type; #else -# if SANITIZER_OPENBSD || defined(__s390__) && !defined(__s390x__) || \ - SANITIZER_EMSCRIPTEN +# if defined(__s390__) && !defined(__s390x__) || SANITIZER_EMSCRIPTEN // Special case: 31-bit s390 has unsigned long as size_t. typedef unsigned long operator_new_size_type; # else @@ -197,9 +195,6 @@ typedef u64 tid_t; // This header should NOT include any other headers to avoid portability issues. // Common defs. -#ifndef INLINE -#define INLINE inline -#endif #define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE #define SANITIZER_WEAK_DEFAULT_IMPL \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE @@ -334,14 +329,10 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond, #define UNIMPLEMENTED() UNREACHABLE("unimplemented") -#define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__) +#define COMPILER_CHECK(pred) static_assert(pred, "") #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) -#define IMPL_PASTE(a, b) a##b -#define IMPL_COMPILER_ASSERT(pred, line) \ - typedef char IMPL_PASTE(assertion_failed_##_, line)[2*(int)(pred)-1] - // Limits for integral types. We have to redefine it in case we don't // have stdint.h (like in Visual Studio 9). #undef __INT64_C @@ -456,5 +447,8 @@ using namespace __sanitizer; namespace __hwasan { using namespace __sanitizer; } +namespace __memprof { +using namespace __sanitizer; +} #endif // SANITIZER_DEFS_H diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h index 3d5db35d68ba5..ec0a6ded009b0 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h @@ -72,6 +72,8 @@ unsigned int internal_sleep(unsigned int seconds); uptr internal_getpid(); uptr internal_getppid(); +int internal_dlinfo(void *handle, int request, void *p); + // Threading uptr internal_sched_yield(); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp index eb9bb765013da..9ea19bc21fa3c 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp @@ -9,7 +9,7 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ - SANITIZER_NETBSD || SANITIZER_OPENBSD + SANITIZER_NETBSD #include "sanitizer_libignore.h" #include "sanitizer_flags.h" diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index dc5bbb6bc6cc6..d1738e0c2aecf 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #include "sanitizer_common.h" #include "sanitizer_flags.h" @@ -26,7 +26,7 @@ #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_GO #include #endif @@ -38,6 +38,14 @@ #include #include #define stat kernel_stat +#if SANITIZER_GO +#undef st_atime +#undef st_mtime +#undef st_ctime +#define st_atime st_atim +#define st_mtime st_mtim +#define st_ctime st_ctim +#endif #include #undef stat #endif @@ -59,13 +67,7 @@ #include #include #include -#if !SANITIZER_OPENBSD #include -#endif -#if SANITIZER_OPENBSD -#include -#include -#endif #include #if SANITIZER_LINUX @@ -137,7 +139,7 @@ const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; #endif // Note : FreeBSD had implemented both -// Linux and OpenBSD apis, available from +// Linux apis, available from // future 12.x version most likely #if SANITIZER_LINUX && defined(__NR_getrandom) # if !defined(GRND_NONBLOCK) @@ -148,20 +150,18 @@ const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; # define SANITIZER_USE_GETRANDOM 0 #endif // SANITIZER_LINUX && defined(__NR_getrandom) -#if SANITIZER_OPENBSD -# define SANITIZER_USE_GETENTROPY 1 +#if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000 +# define SANITIZER_USE_GETENTROPY 1 #else -# if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000 -# define SANITIZER_USE_GETENTROPY 1 -# else -# define SANITIZER_USE_GETENTROPY 0 -# endif -#endif // SANITIZER_USE_GETENTROPY +# define SANITIZER_USE_GETENTROPY 0 +#endif namespace __sanitizer { #if SANITIZER_LINUX && defined(__x86_64__) #include "sanitizer_syscall_linux_x86_64.inc" +#elif SANITIZER_LINUX && SANITIZER_RISCV64 +#include "sanitizer_syscall_linux_riscv64.inc" #elif SANITIZER_LINUX && defined(__aarch64__) #include "sanitizer_syscall_linux_aarch64.inc" #elif SANITIZER_LINUX && defined(__arm__) @@ -172,7 +172,7 @@ namespace __sanitizer { // --------------- sanitizer_libc.h #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD -#if !SANITIZER_S390 && !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN +#if !SANITIZER_S390 && !SANITIZER_EMSCRIPTEN uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset) { #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS @@ -185,20 +185,22 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, offset / 4096); #endif } -#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD && !SANITIZER_NETBSD +#endif // !SANITIZER_S390 && !SANITIZER_NETBSD -#if !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN +#if !SANITIZER_EMSCRIPTEN uptr internal_munmap(void *addr, uptr length) { return internal_syscall(SYSCALL(munmap), (uptr)addr, length); } -#endif -#if !SANITIZER_OPENBSD int internal_mprotect(void *addr, uptr length, int prot) { return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); } #endif +int internal_madvise(uptr addr, uptr length, int advice) { + return internal_syscall(SYSCALL(madvise), addr, length, advice); +} + uptr internal_close(fd_t fd) { #if SANITIZER_EMSCRIPTEN return __wasi_fd_close(fd); @@ -291,9 +293,11 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) { // Undefine compatibility macros from // so that they would not clash with the kernel_stat // st_[a|m|c]time fields +#if !SANITIZER_GO #undef st_atime #undef st_mtime #undef st_ctime +#endif #if defined(SANITIZER_ANDROID) // Bionic sys/stat.h defines additional macros // for compatibility with the old NDKs and @@ -336,7 +340,7 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { #endif uptr internal_stat(const char *path, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD +#if SANITIZER_FREEBSD return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, @@ -360,7 +364,7 @@ uptr internal_stat(const char *path, void *buf) { } uptr internal_lstat(const char *path, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD +#if SANITIZER_FREEBSD return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, AT_SYMLINK_NOFOLLOW); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS @@ -385,9 +389,8 @@ uptr internal_lstat(const char *path, void *buf) { } uptr internal_fstat(fd_t fd, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD || \ - SANITIZER_LINUX_USES_64BIT_SYSCALLS -#if SANITIZER_MIPS64 && !SANITIZER_OPENBSD +#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS +#if SANITIZER_MIPS64 // For mips64, fstat syscall fills buffer in the format of kernel_stat struct kernel_stat kbuf; int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); @@ -427,16 +430,13 @@ uptr internal_readlink(const char *path, char *buf, uptr bufsize) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, bufsize); -#elif SANITIZER_OPENBSD - return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, - bufsize); #else return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize); #endif } uptr internal_unlink(const char *path) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0); #else return internal_syscall(SYSCALL(unlink), (uptr)path); @@ -447,7 +447,7 @@ uptr internal_rename(const char *oldpath, const char *newpath) { #if defined(__riscv) return internal_syscall(SYSCALL(renameat2), AT_FDCWD, (uptr)oldpath, AT_FDCWD, (uptr)newpath, 0); -#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, (uptr)newpath); #else @@ -463,16 +463,6 @@ uptr internal_sched_yield() { #endif } -void internal__exit(int exitcode) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD - internal_syscall(SYSCALL(exit), exitcode); -#else - internal_syscall(SYSCALL(exit_group), exitcode); -#endif - Die(); // Unreachable. -} - - #if !SANITIZER_EMSCRIPTEN unsigned int internal_sleep(unsigned int seconds) { struct timespec ts; @@ -491,6 +481,17 @@ uptr internal_execve(const char *filename, char *const argv[], #endif // !SANITIZER_EMSCRIPTEN #endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if !SANITIZER_NETBSD +void internal__exit(int exitcode) { +#if SANITIZER_FREEBSD || SANITIZER_SOLARIS + internal_syscall(SYSCALL(exit), exitcode); +#else + internal_syscall(SYSCALL(exit_group), exitcode); +#endif + Die(); // Unreachable. +} +#endif // !SANITIZER_NETBSD + // ----------------- sanitizer_common.h bool FileExists(const char *filename) { if (ShouldMockFailureToOpen(filename)) @@ -512,8 +513,6 @@ tid_t GetTid() { long Tid; thr_self(&Tid); return Tid; -#elif SANITIZER_OPENBSD - return internal_syscall(SYSCALL(getthrid)); #elif SANITIZER_SOLARIS return thr_self(); #elif SANITIZER_EMSCRIPTEN @@ -529,9 +528,6 @@ int TgKill(pid_t pid, tid_t tid, int sig) { return internal_syscall(SYSCALL(tgkill), pid, tid, sig); #elif SANITIZER_FREEBSD return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig); -#elif SANITIZER_OPENBSD - (void)pid; - return internal_syscall(SYSCALL(thrkill), tid, sig, nullptr); #elif SANITIZER_SOLARIS (void)pid; return thr_kill(tid, sig); @@ -542,7 +538,7 @@ int TgKill(pid_t pid, tid_t tid, int sig) { #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN u64 NanoTime() { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD +#if SANITIZER_FREEBSD timeval tv; #else kernel_timeval tv; @@ -569,8 +565,7 @@ uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { // 'environ' array (on some others) and does not use libc. This function // should be called first inside __asan_init. const char *GetEnv(const char *name) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ - SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN if (::environ != 0) { uptr NameLen = internal_strlen(name); for (char **Env = ::environ; *Env != 0; Env++) { @@ -608,14 +603,13 @@ const char *GetEnv(const char *name) { #endif } -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_GO extern "C" { SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; } #endif -#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \ - !SANITIZER_OPENBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD static void ReadNullSepFileToArray(const char *path, char ***arr, int arr_size) { char *buff; @@ -640,7 +634,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr, } #endif -#if !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN +#if !SANITIZER_EMSCRIPTEN static void GetArgsAndEnv(char ***argv, char ***envp) { #if SANITIZER_FREEBSD // On FreeBSD, retrieving the argument and environment arrays is done via the @@ -660,16 +654,21 @@ static void GetArgsAndEnv(char ***argv, char ***envp) { #else // SANITIZER_FREEBSD #if !SANITIZER_GO if (&__libc_stack_end) { -#endif // !SANITIZER_GO uptr* stack_end = (uptr*)__libc_stack_end; - int argc = *stack_end; + // Normally argc can be obtained from *stack_end, however, on ARM glibc's + // _start clobbers it: + // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75 + // Do not special-case ARM and infer argc from argv everywhere. + int argc = 0; + while (stack_end[argc + 1]) argc++; *argv = (char**)(stack_end + 1); *envp = (char**)(stack_end + argc + 2); -#if !SANITIZER_GO } else { +#endif // !SANITIZER_GO static const int kMaxArgv = 2000, kMaxEnvp = 2000; ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv); ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); +#if !SANITIZER_GO } #endif // !SANITIZER_GO #endif // SANITIZER_FREEBSD @@ -687,7 +686,7 @@ char **GetEnviron() { return envp; } -#endif // !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN +#endif // !SANITIZER_EMSCRIPTEN #if !SANITIZER_SOLARIS enum MutexState { @@ -748,19 +747,9 @@ void BlockingMutex::CheckLocked() { // 32-bit syscall here. #if SANITIZER_NETBSD // Not used -#elif SANITIZER_OPENBSD -// struct dirent is different for Linux and us. At this moment, we use only -// d_fileno (Linux call this d_ino), d_reclen, and d_name. -struct linux_dirent { - u64 d_ino; // d_fileno - u16 d_reclen; - u16 d_namlen; // not used - u8 d_type; // not used - char d_name[NAME_MAX + 1]; -}; #else struct linux_dirent { -#if SANITIZER_X32 || defined(__aarch64__) +#if SANITIZER_X32 || defined(__aarch64__) || SANITIZER_RISCV64 u64 d_ino; u64 d_off; #else @@ -768,7 +757,7 @@ struct linux_dirent { unsigned long d_off; #endif unsigned short d_reclen; -#ifdef __aarch64__ +#if defined(__aarch64__) || SANITIZER_RISCV64 unsigned char d_type; #endif char d_name[256]; @@ -797,6 +786,14 @@ uptr internal_getppid() { return internal_syscall(SYSCALL(getppid)); } +int internal_dlinfo(void *handle, int request, void *p) { +#if SANITIZER_FREEBSD + return dlinfo(handle, request, p); +#else + UNIMPLEMENTED(); +#endif +} + uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { #if SANITIZER_FREEBSD return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); @@ -839,28 +836,39 @@ int internal_fork() { #endif } -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD +#if SANITIZER_FREEBSD int internal_sysctl(const int *name, unsigned int namelen, void *oldp, uptr *oldlenp, const void *newp, uptr newlen) { -#if SANITIZER_OPENBSD - return sysctl(name, namelen, oldp, (size_t *)oldlenp, (void *)newp, - (size_t)newlen); -#else return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp, (size_t *)oldlenp, newp, (size_t)newlen); -#endif } -#if SANITIZER_FREEBSD int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, const void *newp, uptr newlen) { - static decltype(sysctlbyname) *real = nullptr; - if (!real) - real = (decltype(sysctlbyname) *)dlsym(RTLD_NEXT, "sysctlbyname"); - CHECK(real); - return real(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen); -} + // Note: this function can be called during startup, so we need to avoid + // calling any interceptable functions. On FreeBSD >= 1300045 sysctlbyname() + // is a real syscall, but for older versions it calls sysctlnametomib() + // followed by sysctl(). To avoid calling the intercepted version and + // asserting if this happens during startup, call the real sysctlnametomib() + // followed by internal_sysctl() if the syscall is not available. +#ifdef SYS___sysctlbyname + return internal_syscall(SYSCALL(__sysctlbyname), sname, + internal_strlen(sname), oldp, (size_t *)oldlenp, newp, + (size_t)newlen); +#else + static decltype(sysctlnametomib) *real_sysctlnametomib = nullptr; + if (!real_sysctlnametomib) + real_sysctlnametomib = + (decltype(sysctlnametomib) *)dlsym(RTLD_NEXT, "sysctlnametomib"); + CHECK(real_sysctlnametomib); + + int oid[CTL_MAXNAME]; + size_t len = CTL_MAXNAME; + if (real_sysctlnametomib(sname, oid, &len) == -1) + return (-1); + return internal_sysctl(oid, len, oldp, oldlenp, newp, newlen); #endif +} #endif #if SANITIZER_LINUX @@ -914,16 +922,15 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { -#if SANITIZER_FREEBSD || SANITIZER_OPENBSD +#if SANITIZER_FREEBSD return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); #elif SANITIZER_EMSCRIPTEN return NULL; #else __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; - return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, - (uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0], - sizeof(__sanitizer_kernel_sigset_t)); + return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)k_set, + (uptr)k_oldset, sizeof(__sanitizer_kernel_sigset_t)); #endif } @@ -1080,9 +1087,8 @@ static uptr GetKernelAreaSize() { // is modified (e.g. under schroot) so check this as well. struct utsname uname_info; int pers = personality(0xffffffffUL); - if (!(pers & PER_MASK) - && uname(&uname_info) == 0 - && internal_strstr(uname_info.machine, "64")) + if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 && + internal_strstr(uname_info.machine, "64")) return 0; #endif // SANITIZER_ANDROID @@ -1095,7 +1101,7 @@ static uptr GetKernelAreaSize() { #endif // SANITIZER_WORDSIZE == 32 uptr GetMaxVirtualAddress() { -#if (SANITIZER_NETBSD || SANITIZER_OPENBSD) && defined(__x86_64__) +#if SANITIZER_NETBSD && defined(__x86_64__) return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE) #elif SANITIZER_WORDSIZE == 64 # if defined(__powerpc64__) || defined(__aarch64__) @@ -1107,6 +1113,8 @@ uptr GetMaxVirtualAddress() { // This should (does) work for both PowerPC64 Endian modes. // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit. return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; +#elif SANITIZER_RISCV64 + return (1ULL << 38) - 1; # elif defined(__mips64) return (1ULL << 40) - 1; // 0x000000ffffffffffUL; # elif defined(__s390x__) @@ -1137,7 +1145,8 @@ uptr GetMaxUserVirtualAddress() { #if !SANITIZER_ANDROID uptr GetPageSize() { -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \ + defined(EXEC_PAGESIZE) return EXEC_PAGESIZE; #elif SANITIZER_FREEBSD || SANITIZER_NETBSD // Use sysctl as sysconf can trigger interceptors internally. @@ -1157,7 +1166,6 @@ uptr GetPageSize() { extern "C" uptr emscripten_get_module_name(char *buf, uptr buf_len); #endif -#if !SANITIZER_OPENBSD uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { #if SANITIZER_SOLARIS const char *default_module_name = getexecname(); @@ -1196,7 +1204,6 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { return module_name_len; #endif } -#endif // !SANITIZER_OPENBSD uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { #if SANITIZER_LINUX @@ -1229,10 +1236,10 @@ bool LibraryNameIs(const char *full_name, const char *base_name) { // Call cb for each region mapped by map. void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) { CHECK_NE(map, nullptr); -#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD +#if !SANITIZER_FREEBSD typedef ElfW(Phdr) Elf_Phdr; typedef ElfW(Ehdr) Elf_Ehdr; -#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD +#endif // !SANITIZER_FREEBSD char *base = (char *)map->l_addr; Elf_Ehdr *ehdr = (Elf_Ehdr *)base; char *phdrs = base + ehdr->e_phoff; @@ -1404,6 +1411,55 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, : "memory", "$29" ); return res; } +#elif SANITIZER_RISCV64 +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; + + register int (*__fn)(void *) __asm__("a0") = fn; + register void *__stack __asm__("a1") = child_stack; + register int __flags __asm__("a2") = flags; + register void *__arg __asm__("a3") = arg; + register int *__ptid __asm__("a4") = parent_tidptr; + register void *__tls __asm__("a5") = newtls; + register int *__ctid __asm__("a6") = child_tidptr; + + __asm__ __volatile__( + "mv a0,a2\n" /* flags */ + "mv a2,a4\n" /* ptid */ + "mv a3,a5\n" /* tls */ + "mv a4,a6\n" /* ctid */ + "addi a7, zero, %9\n" /* clone */ + + "ecall\n" + + /* if (%r0 != 0) + * return %r0; + */ + "bnez a0, 1f\n" + + /* In the child, now. Call "fn(arg)". */ + "ld a0, 8(sp)\n" + "ld a1, 16(sp)\n" + "jalr a1\n" + + /* Call _exit(%r0). */ + "addi a7, zero, %10\n" + "ecall\n" + "1:\n" + + : "=r"(res) + : "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit) + : "ra", "memory"); + return res; +} #elif defined(__aarch64__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { @@ -1697,6 +1753,12 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, } #endif // defined(__x86_64__) && SANITIZER_LINUX +#if SANITIZER_LINUX +int internal_uname(struct utsname *buf) { + return internal_syscall(SYSCALL(uname), buf); +} +#endif + #if SANITIZER_ANDROID #if __ANDROID_API__ < 21 extern "C" __attribute__((weak)) int dl_iterate_phdr( @@ -1779,7 +1841,7 @@ HandleSignalMode GetHandleSignalMode(int signum) { } #if !SANITIZER_GO -void *internal_start_thread(void(*func)(void *arg), void *arg) { +void *internal_start_thread(void *(*func)(void *arg), void *arg) { // Start the thread with signals blocked, otherwise it can steal user signals. __sanitizer_sigset_t set, old; internal_sigfillset(&set); @@ -1790,7 +1852,7 @@ void *internal_start_thread(void(*func)(void *arg), void *arg) { #endif internal_sigprocmask(SIG_SETMASK, &set, &old); void *th; - real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg); + real_pthread_create(&th, nullptr, func, arg); internal_sigprocmask(SIG_SETMASK, &old, nullptr); return th; } @@ -1799,7 +1861,7 @@ void internal_join_thread(void *th) { real_pthread_join(th, nullptr); } #else -void *internal_start_thread(void (*func)(void *), void *arg) { return 0; } +void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; } void internal_join_thread(void *th) {} #endif @@ -1827,11 +1889,7 @@ static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { } #endif -#if SANITIZER_OPENBSD -using Context = sigcontext; -#else using Context = ucontext_t; -#endif SignalContext::WriteFlag SignalContext::GetWriteFlag() const { Context *ucontext = (Context *)context; @@ -1841,8 +1899,6 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const { uptr err = ucontext->uc_mcontext.mc_err; #elif SANITIZER_NETBSD uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR]; -#elif SANITIZER_OPENBSD - uptr err = ucontext->sc_err; #elif SANITIZER_SOLARIS && defined(__i386__) const int Err = 13; uptr err = ucontext->uc_mcontext.gregs[Err]; @@ -1924,6 +1980,105 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const { #endif u32 instr = *(u32 *)pc; return (instr >> 21) & 1 ? WRITE: READ; +#elif defined(__riscv) + unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC]; + unsigned faulty_instruction = *(uint16_t *)pc; + +#if defined(__riscv_compressed) + if ((faulty_instruction & 0x3) != 0x3) { // it's a compressed instruction + // set op_bits to the instruction bits [1, 0, 15, 14, 13] + unsigned op_bits = + ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13); + unsigned rd = faulty_instruction & 0xF80; // bits 7-11, inclusive + switch (op_bits) { + case 0b10'010: // c.lwsp (rd != x0) +#if __riscv_xlen == 64 + case 0b10'011: // c.ldsp (rd != x0) +#endif + return rd ? SignalContext::READ : SignalContext::UNKNOWN; + case 0b00'010: // c.lw +#if __riscv_flen >= 32 && __riscv_xlen == 32 + case 0b10'011: // c.flwsp +#endif +#if __riscv_flen >= 32 || __riscv_xlen == 64 + case 0b00'011: // c.flw / c.ld +#endif +#if __riscv_flen == 64 + case 0b00'001: // c.fld + case 0b10'001: // c.fldsp +#endif + return SignalContext::READ; + case 0b00'110: // c.sw + case 0b10'110: // c.swsp +#if __riscv_flen >= 32 || __riscv_xlen == 64 + case 0b00'111: // c.fsw / c.sd + case 0b10'111: // c.fswsp / c.sdsp +#endif +#if __riscv_flen == 64 + case 0b00'101: // c.fsd + case 0b10'101: // c.fsdsp +#endif + return SignalContext::WRITE; + default: + return SignalContext::UNKNOWN; + } + } +#endif + + unsigned opcode = faulty_instruction & 0x7f; // lower 7 bits + unsigned funct3 = (faulty_instruction >> 12) & 0x7; // bits 12-14, inclusive + switch (opcode) { + case 0b0000011: // loads + switch (funct3) { + case 0b000: // lb + case 0b001: // lh + case 0b010: // lw +#if __riscv_xlen == 64 + case 0b011: // ld +#endif + case 0b100: // lbu + case 0b101: // lhu + return SignalContext::READ; + default: + return SignalContext::UNKNOWN; + } + case 0b0100011: // stores + switch (funct3) { + case 0b000: // sb + case 0b001: // sh + case 0b010: // sw +#if __riscv_xlen == 64 + case 0b011: // sd +#endif + return SignalContext::WRITE; + default: + return SignalContext::UNKNOWN; + } +#if __riscv_flen >= 32 + case 0b0000111: // floating-point loads + switch (funct3) { + case 0b010: // flw +#if __riscv_flen == 64 + case 0b011: // fld +#endif + return SignalContext::READ; + default: + return SignalContext::UNKNOWN; + } + case 0b0100111: // floating-point stores + switch (funct3) { + case 0b010: // fsw +#if __riscv_flen == 64 + case 0b011: // fsd +#endif + return SignalContext::WRITE; + default: + return SignalContext::UNKNOWN; + } +#endif + default: + return SignalContext::UNKNOWN; + } #else (void)ucontext; return UNKNOWN; // FIXME: Implement. @@ -1969,11 +2124,6 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.mc_rip; *bp = ucontext->uc_mcontext.mc_rbp; *sp = ucontext->uc_mcontext.mc_rsp; -#elif SANITIZER_OPENBSD - sigcontext *ucontext = (sigcontext *)context; - *pc = ucontext->sc_rip; - *bp = ucontext->sc_rbp; - *sp = ucontext->sc_rsp; # else ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.gregs[REG_RIP]; @@ -1986,11 +2136,6 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.mc_eip; *bp = ucontext->uc_mcontext.mc_ebp; *sp = ucontext->uc_mcontext.mc_esp; -#elif SANITIZER_OPENBSD - sigcontext *ucontext = (sigcontext *)context; - *pc = ucontext->sc_eip; - *bp = ucontext->sc_ebp; - *sp = ucontext->sc_esp; # else ucontext_t *ucontext = (ucontext_t*)context; # if SANITIZER_SOLARIS @@ -2002,13 +2147,13 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { # ifndef REG_EBP # define REG_EBP 6 // REG_FP # endif -# ifndef REG_ESP -# define REG_ESP 17 // REG_SP +# ifndef REG_UESP +# define REG_UESP 17 // REG_SP # endif # endif *pc = ucontext->uc_mcontext.gregs[REG_EIP]; *bp = ucontext->uc_mcontext.gregs[REG_EBP]; - *sp = ucontext->uc_mcontext.gregs[REG_ESP]; + *sp = ucontext->uc_mcontext.gregs[REG_UESP]; # endif #elif defined(__powerpc__) || defined(__powerpc64__) ucontext_t *ucontext = (ucontext_t*)context; @@ -2087,7 +2232,9 @@ void CheckASLR() { } if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) { - Printf("This sanitizer is not compatible with enabled ASLR\n"); + Printf("This sanitizer is not compatible with enabled ASLR.\n" + "To disable ASLR, please run \"paxctl +a %s\" and try again.\n", + GetArgv()[0]); Die(); } #elif SANITIZER_PPC64V2 @@ -2159,14 +2306,12 @@ void CheckMPROTECT() { #endif } -void PrintModuleMap() { } - void CheckNoDeepBind(const char *filename, int flag) { #ifdef RTLD_DEEPBIND if (flag & RTLD_DEEPBIND) { Report( "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag" - " which is incompatibe with sanitizer runtime " + " which is incompatible with sanitizer runtime " "(see https://github.com/google/sanitizers/issues/611 for details" "). If you want to run %s library under sanitizers please remove " "RTLD_DEEPBIND from dlopen flags.\n", diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h index d73b539c3cdb8..bb432f75aa86a 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -14,17 +14,17 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" #include "sanitizer_platform_limits_freebsd.h" #include "sanitizer_platform_limits_netbsd.h" -#include "sanitizer_platform_limits_openbsd.h" #include "sanitizer_platform_limits_posix.h" #include "sanitizer_platform_limits_solaris.h" #include "sanitizer_posix.h" struct link_map; // Opaque type returned by dlopen(). +struct utsname; namespace __sanitizer { // Dirent structure for getdents(). Note that this structure is different from @@ -59,12 +59,13 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5); // internal_sigaction instead. int internal_sigaction_norestorer(int signum, const void *act, void *oldact); void internal_sigdelset(__sanitizer_sigset_t *set, int signum); -#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \ - || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) \ - || defined(__arm__) +#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \ + defined(__arm__) || SANITIZER_RISCV64 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr); #endif +int internal_uname(struct utsname *buf); #elif SANITIZER_FREEBSD void internal_sigdelset(__sanitizer_sigset_t *set, int signum); #elif SANITIZER_NETBSD @@ -107,7 +108,7 @@ void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)); // Releases memory pages entirely within the [beg, end] address range. // The pages no longer count toward RSS; reads are guaranteed to return 0. // Requires (but does not verify!) that pages are MAP_PRIVATE. -INLINE void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) { +inline void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) { // man madvise on Linux promises zero-fill for anonymous private pages. // Testing shows the same behaviour for private (but not anonymous) mappings // of shm_open() files, as long as the underlying file is untouched. diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp index edbe8402808a8..f20b9001c2c20 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -13,8 +13,8 @@ #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ + SANITIZER_SOLARIS #include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" @@ -28,6 +28,10 @@ #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" +#if SANITIZER_NETBSD +#define _RTLD_SOURCE // for __lwp_gettcb_fast() / __lwp_getprivate_fast() +#endif + #include // for dlsym() #include #include @@ -35,6 +39,10 @@ #include #include +#if !defined(ElfW) +#define ElfW(type) Elf_##type +#endif + #if SANITIZER_FREEBSD #include #include @@ -42,11 +50,6 @@ #define pthread_getattr_np pthread_attr_get_np #endif -#if SANITIZER_OPENBSD -#include -#include -#endif - #if SANITIZER_NETBSD #include #include @@ -134,18 +137,13 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, CHECK_EQ(thr_stksegment(&ss), 0); stacksize = ss.ss_size; stackaddr = (char *)ss.ss_sp - stacksize; -#elif SANITIZER_OPENBSD - stack_t sattr; - CHECK_EQ(pthread_stackseg_np(pthread_self(), &sattr), 0); - stackaddr = sattr.ss_sp; - stacksize = sattr.ss_size; #else // !SANITIZER_SOLARIS pthread_attr_t attr; pthread_attr_init(&attr); CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); my_pthread_attr_getstack(&attr, &stackaddr, &stacksize); pthread_attr_destroy(&attr); -#endif // SANITIZER_SOLARIS +#endif // SANITIZER_SOLARIS *stack_top = (uptr)stackaddr + stacksize; *stack_bottom = (uptr)stackaddr; @@ -185,20 +183,19 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor, #endif } -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \ - !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_SOLARIS +#if SANITIZER_GLIBC && !SANITIZER_GO static uptr g_tls_size; #ifdef __i386__ -# define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27)) +#define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27)) #else -# define CHECK_GET_TLS_STATIC_INFO_VERSION 0 +#define CHECK_GET_TLS_STATIC_INFO_VERSION 0 #endif #if CHECK_GET_TLS_STATIC_INFO_VERSION -# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) +#define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) #else -# define DL_INTERNAL_FUNCTION +#define DL_INTERNAL_FUNCTION #endif namespace { @@ -258,12 +255,11 @@ void InitTlsSize() { } #else void InitTlsSize() { } -#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && - // !SANITIZER_NETBSD && !SANITIZER_SOLARIS +#endif // SANITIZER_GLIBC && !SANITIZER_GO -#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \ - defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \ - defined(__arm__)) && \ +#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \ + defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \ + defined(__arm__) || SANITIZER_RISCV64) && \ SANITIZER_LINUX && !SANITIZER_ANDROID // sizeof(struct pthread) from glibc. static atomic_uintptr_t thread_descriptor_size; @@ -297,12 +293,29 @@ uptr ThreadDescriptorSize() { val = FIRST_32_SECOND_64(1168, 2288); else if (minor <= 14) val = FIRST_32_SECOND_64(1168, 2304); - else + else if (minor < 32) // Unknown version val = FIRST_32_SECOND_64(1216, 2304); + else // minor == 32 + val = FIRST_32_SECOND_64(1344, 2496); } #elif defined(__mips__) // TODO(sagarthakur): add more values as per different glibc versions. val = FIRST_32_SECOND_64(1152, 1776); +#elif SANITIZER_RISCV64 + int major; + int minor; + int patch; + if (GetLibcVersion(&major, &minor, &patch) && major == 2) { + // TODO: consider adding an optional runtime check for an unknown (untested) + // glibc version + if (minor <= 28) // WARNING: the highest tested version is 2.29 + val = 1772; // no guarantees for this one + else if (minor <= 31) + val = 1772; // tested against glibc 2.29, 2.31 + else + val = 1936; // tested against glibc 2.32 + } + #elif defined(__aarch64__) // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22. val = 1776; @@ -323,15 +336,17 @@ uptr ThreadSelfOffset() { return kThreadSelfOffset; } -#if defined(__mips__) || defined(__powerpc64__) +#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 // TlsPreTcbSize includes size of struct pthread_descr and size of tcb // head structure. It lies before the static tls blocks. static uptr TlsPreTcbSize() { -# if defined(__mips__) +#if defined(__mips__) const uptr kTcbHead = 16; // sizeof (tcbhead_t) -# elif defined(__powerpc64__) +#elif defined(__powerpc64__) const uptr kTcbHead = 88; // sizeof (tcbhead_t) -# endif +#elif SANITIZER_RISCV64 + const uptr kTcbHead = 16; // sizeof (tcbhead_t) +#endif const uptr kTlsAlign = 16; const uptr kTlsPreTcbSize = RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign); @@ -341,11 +356,11 @@ static uptr TlsPreTcbSize() { uptr ThreadSelf() { uptr descr_addr; -# if defined(__i386__) +#if defined(__i386__) asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset)); -# elif defined(__x86_64__) +#elif defined(__x86_64__) asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset)); -# elif defined(__mips__) +#elif defined(__mips__) // MIPS uses TLS variant I. The thread pointer (in hardware register $29) // points to the end of the TCB + 0x7000. The pthread_descr structure is // immediately in front of the TCB. TlsPreTcbSize() includes the size of the @@ -357,12 +372,16 @@ uptr ThreadSelf() { rdhwr %0,$29;\ .set pop" : "=r" (thread_pointer)); descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); -# elif defined(__aarch64__) || defined(__arm__) +#elif defined(__aarch64__) || defined(__arm__) descr_addr = reinterpret_cast(__builtin_thread_pointer()) - ThreadDescriptorSize(); -# elif defined(__s390__) +#elif SANITIZER_RISCV64 + // https://github.com/riscv/riscv-elf-psabi-doc/issues/53 + uptr thread_pointer = reinterpret_cast(__builtin_thread_pointer()); + descr_addr = thread_pointer - TlsPreTcbSize(); +#elif defined(__s390__) descr_addr = reinterpret_cast(__builtin_thread_pointer()); -# elif defined(__powerpc64__) +#elif defined(__powerpc64__) // PPC64LE uses TLS variant I. The thread pointer (in GPR 13) // points to the end of the TCB + 0x7000. The pthread_descr structure is // immediately in front of the TCB. TlsPreTcbSize() includes the size of the @@ -371,9 +390,9 @@ uptr ThreadSelf() { uptr thread_pointer; asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset)); descr_addr = thread_pointer - TlsPreTcbSize(); -# else -# error "unsupported CPU arch" -# endif +#else +#error "unsupported CPU arch" +#endif return descr_addr; } #endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX @@ -381,15 +400,15 @@ uptr ThreadSelf() { #if SANITIZER_FREEBSD static void **ThreadSelfSegbase() { void **segbase = 0; -# if defined(__i386__) +#if defined(__i386__) // sysarch(I386_GET_GSBASE, segbase); __asm __volatile("mov %%gs:0, %0" : "=r" (segbase)); -# elif defined(__x86_64__) +#elif defined(__x86_64__) // sysarch(AMD64_GET_FSBASE, segbase); __asm __volatile("movq %%fs:0, %0" : "=r" (segbase)); -# else -# error "unsupported CPU arch" -# endif +#else +#error "unsupported CPU arch" +#endif return segbase; } @@ -400,7 +419,13 @@ uptr ThreadSelf() { #if SANITIZER_NETBSD static struct tls_tcb * ThreadSelfTlsTcb() { - return (struct tls_tcb *)_lwp_getprivate(); + struct tls_tcb *tcb = nullptr; +#ifdef __HAVE___LWP_GETTCB_FAST + tcb = (struct tls_tcb *)__lwp_gettcb_fast(); +#elif defined(__HAVE___LWP_GETPRIVATE_FAST) + tcb = (struct tls_tcb *)__lwp_getprivate_fast(); +#endif + return tcb; } uptr ThreadSelf() { @@ -421,22 +446,40 @@ int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) { } #endif // SANITIZER_NETBSD +#if SANITIZER_ANDROID +// Bionic provides this API since S. +extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_get_static_tls_bounds(void **, + void **); +#endif + #if !SANITIZER_GO static void GetTls(uptr *addr, uptr *size) { -#if SANITIZER_LINUX && !SANITIZER_ANDROID -# if defined(__x86_64__) || defined(__i386__) || defined(__s390__) +#if SANITIZER_ANDROID + if (&__libc_get_static_tls_bounds) { + void *start_addr; + void *end_addr; + __libc_get_static_tls_bounds(&start_addr, &end_addr); + *addr = reinterpret_cast(start_addr); + *size = + reinterpret_cast(end_addr) - reinterpret_cast(start_addr); + } else { + *addr = 0; + *size = 0; + } +#elif SANITIZER_LINUX +#if defined(__x86_64__) || defined(__i386__) || defined(__s390__) *addr = ThreadSelf(); *size = GetTlsSize(); *addr -= *size; *addr += ThreadDescriptorSize(); -# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \ - || defined(__arm__) +#elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \ + defined(__arm__) || SANITIZER_RISCV64 *addr = ThreadSelf(); *size = GetTlsSize(); -# else +#else *addr = 0; *size = 0; -# endif +#endif #elif SANITIZER_FREEBSD void** segbase = ThreadSelfSegbase(); *addr = 0; @@ -464,34 +507,32 @@ static void GetTls(uptr *addr, uptr *size) { *addr = (uptr)tcb->tcb_dtv[1]; } } -#elif SANITIZER_OPENBSD - *addr = 0; - *size = 0; -#elif SANITIZER_ANDROID - *addr = 0; - *size = 0; #elif SANITIZER_SOLARIS // FIXME *addr = 0; *size = 0; #else -# error "Unknown OS" +#error "Unknown OS" #endif } #endif #if !SANITIZER_GO uptr GetTlsSize() { -#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \ + SANITIZER_SOLARIS uptr addr, size; GetTls(&addr, &size); return size; -#elif defined(__mips__) || defined(__powerpc64__) +#elif SANITIZER_GLIBC +#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16); #else return g_tls_size; #endif +#else + return 0; +#endif } #endif @@ -520,13 +561,13 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, #endif } -#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD +#if !SANITIZER_FREEBSD typedef ElfW(Phdr) Elf_Phdr; -#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 +#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 #define Elf_Phdr XElf32_Phdr #define dl_phdr_info xdl_phdr_info #define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b)) -#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD +#endif // !SANITIZER_FREEBSD struct DlIteratePhdrData { InternalMmapVectorNoCtor *modules; @@ -646,7 +687,7 @@ uptr GetRSS() { // sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used on most platforms as // they allocate memory. u32 GetNumberOfCPUs() { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD u32 ncpu; int req[2]; uptr len = sizeof(ncpu); @@ -701,7 +742,7 @@ u32 GetNumberOfCPUs() { #if SANITIZER_LINUX -# if SANITIZER_ANDROID +#if SANITIZER_ANDROID static atomic_uint8_t android_log_initialized; void AndroidLogInit() { @@ -745,7 +786,7 @@ void SetAbortMessage(const char *str) { if (&android_set_abort_message) android_set_abort_message(str); } -# else +#else void AndroidLogInit() {} static bool ShouldLogAfterPrintf() { return true; } @@ -753,7 +794,7 @@ static bool ShouldLogAfterPrintf() { return true; } void WriteOneLineToSyslog(const char *s) { syslog(LOG_INFO, "%s", s); } void SetAbortMessage(const char *str) {} -# endif // SANITIZER_ANDROID +#endif // SANITIZER_ANDROID void LogMessageOnPrintf(const char *str) { if (common_flags()->log_to_syslog && ShouldLogAfterPrintf()) @@ -768,7 +809,7 @@ void LogMessageOnPrintf(const char *str) { // initialized after the vDSO function pointers, so if it exists, is not null // and is not empty, we can use clock_gettime. extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname; -INLINE bool CanUseVDSO() { +inline bool CanUseVDSO() { // Bionic is safe, it checks for the vDSO function pointers to be initialized. if (SANITIZER_ANDROID) return true; @@ -803,7 +844,6 @@ u64 MonotonicNanoTime() { } #endif // SANITIZER_LINUX && !SANITIZER_GO -#if !SANITIZER_OPENBSD void ReExec() { const char *pathname = "/proc/self/exe"; @@ -835,7 +875,48 @@ void ReExec() { Printf("execve failed, errno %d\n", rverrno); Die(); } -#endif // !SANITIZER_OPENBSD + +void UnmapFromTo(uptr from, uptr to) { + if (to == from) + return; + CHECK(to >= from); + uptr res = internal_munmap(reinterpret_cast(from), to - from); + if (UNLIKELY(internal_iserror(res))) { + Report("ERROR: %s failed to unmap 0x%zx (%zd) bytes at address %p\n", + SanitizerToolName, to - from, to - from, (void *)from); + CHECK("unable to unmap" && 0); + } +} + +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, + UNUSED uptr &high_mem_end) { + const uptr granularity = GetMmapGranularity(); + const uptr alignment = + Max(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); + const uptr left_padding = + Max(granularity, 1ULL << min_shadow_base_alignment); + + const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); + const uptr map_size = shadow_size + left_padding + alignment; + + const uptr map_start = (uptr)MmapNoAccess(map_size); + CHECK_NE(map_start, ~(uptr)0); + + const uptr shadow_start = RoundUpTo(map_start + left_padding, alignment); + + UnmapFromTo(map_start, shadow_start - left_padding); + UnmapFromTo(shadow_start + shadow_size, map_start + map_size); + + return shadow_start; +} + +void InitializePlatformCommonFlags(CommonFlags *cf) { +#if SANITIZER_ANDROID + if (&__libc_get_static_tls_bounds == nullptr) + cf->detect_leaks = false; +#endif +} } // namespace __sanitizer diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp index 9e3b4f13a4365..bb2f5b5f9f7df 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp @@ -15,14 +15,15 @@ #if SANITIZER_LINUX && SANITIZER_S390 -#include "sanitizer_libc.h" -#include "sanitizer_linux.h" - +#include #include #include #include #include +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" + namespace __sanitizer { // --------------- sanitizer_libc.h @@ -123,7 +124,7 @@ static bool FixedCVE_2016_2143() { struct utsname buf; unsigned int major, minor, patch = 0; // This should never fail, but just in case... - if (uname(&buf)) + if (internal_uname(&buf)) return false; const char *ptr = buf.release; major = internal_simple_strtoll(ptr, &ptr, 10); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp index ea4bd02aa92e4..2b53d7d730d7e 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp @@ -27,9 +27,9 @@ #include "sanitizer_flags.h" #include "sanitizer_internal_defs.h" #include "sanitizer_libc.h" -#include "sanitizer_placement_new.h" #include "sanitizer_platform_limits_posix.h" #include "sanitizer_procmaps.h" +#include "sanitizer_ptrauth.h" #if !SANITIZER_IOS #include // for _NSGetEnviron @@ -137,6 +137,10 @@ int internal_mprotect(void *addr, uptr length, int prot) { return mprotect(addr, length, prot); } +int internal_madvise(uptr addr, uptr length, int advice) { + return madvise((void *)addr, length, advice); +} + uptr internal_close(fd_t fd) { return close(fd); } @@ -208,6 +212,10 @@ uptr internal_getpid() { return getpid(); } +int internal_dlinfo(void *handle, int request, void *p) { + UNIMPLEMENTED(); +} + int internal_sigaction(int signum, const void *act, void *oldact) { return sigaction(signum, (const struct sigaction *)act, (struct sigaction *)oldact); @@ -242,7 +250,8 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, (size_t)newlen); } -static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { +static fd_t internal_spawn_impl(const char *argv[], const char *envp[], + pid_t *pid) { fd_t master_fd = kInvalidFd; fd_t slave_fd = kInvalidFd; @@ -298,8 +307,8 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { // posix_spawn char **argv_casted = const_cast(argv); - char **env = GetEnviron(); - res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env); + char **envp_casted = const_cast(envp); + res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted); if (res != 0) return kInvalidFd; // Disable echo in the new terminal, disable CR. @@ -316,7 +325,7 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { return fd; } -fd_t internal_spawn(const char *argv[], pid_t *pid) { +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) { // The client program may close its stdin and/or stdout and/or stderr thus // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this // case the communication is broken if either the parent or the child tries to @@ -331,7 +340,7 @@ fd_t internal_spawn(const char *argv[], pid_t *pid) { break; } - fd_t fd = internal_spawn_impl(argv, pid); + fd_t fd = internal_spawn_impl(argv, envp, pid); for (; count > 0; count--) { internal_close(low_fds[count]); @@ -382,7 +391,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, // pthread_get_stacksize_np() returns an incorrect stack size for the main // thread on Mavericks. See // https://github.com/google/sanitizers/issues/261 - if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization && + if ((GetMacosAlignedVersion() >= MacosVersion(10, 9)) && at_initialization && stacksize == (1 << 19)) { struct rlimit rl; CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); @@ -601,68 +610,132 @@ HandleSignalMode GetHandleSignalMode(int signum) { return result; } -MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; +// Offset example: +// XNU 17 -- macOS 10.13 -- iOS 11 -- tvOS 11 -- watchOS 4 +constexpr u16 GetOSMajorKernelOffset() { + if (TARGET_OS_OSX) return 4; + if (TARGET_OS_IOS || TARGET_OS_TV) return 6; + if (TARGET_OS_WATCH) return 13; +} + +using VersStr = char[64]; + +static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) { + u16 kernel_major = GetDarwinKernelVersion().major; + u16 offset = GetOSMajorKernelOffset(); + CHECK_GE(kernel_major, offset); + u16 os_major = kernel_major - offset; + + const char *format = "%d.0"; + if (TARGET_OS_OSX) { + if (os_major >= 16) { // macOS 11+ + os_major -= 5; + } else { // macOS 10.15 and below + format = "10.%d"; + } + } + return internal_snprintf(vers, sizeof(VersStr), format, os_major); +} -MacosVersion GetMacosVersionInternal() { - int mib[2] = { CTL_KERN, KERN_OSRELEASE }; - char version[100]; - uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]); - for (uptr i = 0; i < maxlen; i++) version[i] = '\0'; - // Get the version length. - CHECK_NE(internal_sysctl(mib, 2, 0, &len, 0, 0), -1); - CHECK_LT(len, maxlen); - CHECK_NE(internal_sysctl(mib, 2, version, &len, 0, 0), -1); +static void GetOSVersion(VersStr vers) { + uptr len = sizeof(VersStr); + if (SANITIZER_IOSSIM) { + const char *vers_env = GetEnv("SIMULATOR_RUNTIME_VERSION"); + if (!vers_env) { + Report("ERROR: Running in simulator but SIMULATOR_RUNTIME_VERSION env " + "var is not set.\n"); + Die(); + } + len = internal_strlcpy(vers, vers_env, len); + } else { + int res = + internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0); + + // XNU 17 (macOS 10.13) and below do not provide the sysctl + // `kern.osproductversion` entry (res != 0). + bool no_os_version = res != 0; + + // For launchd, sanitizer initialization runs before sysctl is setup + // (res == 0 && len != strlen(vers), vers is not a valid version). However, + // the kernel version `kern.osrelease` is available. + bool launchd = (res == 0 && internal_strlen(vers) < 3); + if (launchd) CHECK_EQ(internal_getpid(), 1); + + if (no_os_version || launchd) { + len = ApproximateOSVersionViaKernelVersion(vers); + } + } + CHECK_LT(len, sizeof(VersStr)); +} - // Expect .(.) - CHECK_GE(len, 3); - const char *p = version; - int major = internal_simple_strtoll(p, &p, /*base=*/10); - if (*p != '.') return MACOS_VERSION_UNKNOWN; +void ParseVersion(const char *vers, u16 *major, u16 *minor) { + // Format: .[.]\0 + CHECK_GE(internal_strlen(vers), 3); + const char *p = vers; + *major = internal_simple_strtoll(p, &p, /*base=*/10); + CHECK_EQ(*p, '.'); p += 1; - int minor = internal_simple_strtoll(p, &p, /*base=*/10); - if (*p != '.') return MACOS_VERSION_UNKNOWN; - - switch (major) { - case 9: return MACOS_VERSION_LEOPARD; - case 10: return MACOS_VERSION_SNOW_LEOPARD; - case 11: return MACOS_VERSION_LION; - case 12: return MACOS_VERSION_MOUNTAIN_LION; - case 13: return MACOS_VERSION_MAVERICKS; - case 14: return MACOS_VERSION_YOSEMITE; - case 15: return MACOS_VERSION_EL_CAPITAN; - case 16: return MACOS_VERSION_SIERRA; - case 17: - // Not a typo, 17.5 Darwin Kernel Version maps to High Sierra 10.13.4. - if (minor >= 5) - return MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4; - return MACOS_VERSION_HIGH_SIERRA; - case 18: return MACOS_VERSION_MOJAVE; - case 19: return MACOS_VERSION_CATALINA; - default: - if (major < 9) return MACOS_VERSION_UNKNOWN; - return MACOS_VERSION_UNKNOWN_NEWER; + *minor = internal_simple_strtoll(p, &p, /*base=*/10); +} + +// Aligned versions example: +// macOS 10.15 -- iOS 13 -- tvOS 13 -- watchOS 6 +static void MapToMacos(u16 *major, u16 *minor) { + if (TARGET_OS_OSX) + return; + + if (TARGET_OS_IOS || TARGET_OS_TV) + *major += 2; + else if (TARGET_OS_WATCH) + *major += 9; + else + UNREACHABLE("unsupported platform"); + + if (*major >= 16) { // macOS 11+ + *major -= 5; + } else { // macOS 10.15 and below + *minor = *major; + *major = 10; } } -MacosVersion GetMacosVersion() { - atomic_uint32_t *cache = - reinterpret_cast(&cached_macos_version); - MacosVersion result = - static_cast(atomic_load(cache, memory_order_acquire)); - if (result == MACOS_VERSION_UNINITIALIZED) { - result = GetMacosVersionInternal(); - atomic_store(cache, result, memory_order_release); +static MacosVersion GetMacosAlignedVersionInternal() { + VersStr vers = {}; + GetOSVersion(vers); + + u16 major, minor; + ParseVersion(vers, &major, &minor); + MapToMacos(&major, &minor); + + return MacosVersion(major, minor); +} + +static_assert(sizeof(MacosVersion) == sizeof(atomic_uint32_t::Type), + "MacosVersion cache size"); +static atomic_uint32_t cached_macos_version; + +MacosVersion GetMacosAlignedVersion() { + atomic_uint32_t::Type result = + atomic_load(&cached_macos_version, memory_order_acquire); + if (!result) { + MacosVersion version = GetMacosAlignedVersionInternal(); + result = *reinterpret_cast(&version); + atomic_store(&cached_macos_version, result, memory_order_release); } - return result; + return *reinterpret_cast(&result); } -bool PlatformHasDifferentMemcpyAndMemmove() { - // On OS X 10.7 memcpy() and memmove() are both resolved - // into memmove$VARIANT$sse42. - // See also https://github.com/google/sanitizers/issues/34. - // TODO(glider): need to check dynamically that memcpy() and memmove() are - // actually the same function. - return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD; +DarwinKernelVersion GetDarwinKernelVersion() { + VersStr vers = {}; + uptr len = sizeof(VersStr); + int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0); + CHECK_EQ(res, 0); + CHECK_LT(len, sizeof(VersStr)); + + u16 major, minor; + ParseVersion(vers, &major, &minor); + + return DarwinKernelVersion(major, minor); } uptr GetRSS() { @@ -677,13 +750,13 @@ uptr GetRSS() { return info.resident_size; } -void *internal_start_thread(void(*func)(void *arg), void *arg) { +void *internal_start_thread(void *(*func)(void *arg), void *arg) { // Start the thread with signals blocked, otherwise it can steal user signals. __sanitizer_sigset_t set, old; internal_sigfillset(&set); internal_sigprocmask(SIG_SETMASK, &set, &old); pthread_t th; - pthread_create(&th, 0, (void*(*)(void *arg))func, arg); + pthread_create(&th, 0, func, arg); internal_sigprocmask(SIG_SETMASK, &old, 0); return th; } @@ -711,7 +784,7 @@ void LogFullErrorReport(const char *buffer) { #if !SANITIZER_GO // Log with os_trace. This will make it into the crash log. #if SANITIZER_OS_TRACE - if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) { + if (GetMacosAlignedVersion() >= MacosVersion(10, 10)) { // os_trace requires the message (format parameter) to be a string literal. if (internal_strncmp(SanitizerToolName, "AddressSanitizer", sizeof("AddressSanitizer") - 1) == 0) @@ -760,16 +833,24 @@ bool SignalContext::IsTrueFaultingAddress() const { return si->si_signo == SIGSEGV && si->si_code != 0; } +#if defined(__aarch64__) && defined(arm_thread_state64_get_sp) + #define AARCH64_GET_REG(r) \ + (uptr)ptrauth_strip( \ + (void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0) +#else + #define AARCH64_GET_REG(r) ucontext->uc_mcontext->__ss.__##r +#endif + static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { ucontext_t *ucontext = (ucontext_t*)context; # if defined(__aarch64__) - *pc = ucontext->uc_mcontext->__ss.__pc; + *pc = AARCH64_GET_REG(pc); # if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0 - *bp = ucontext->uc_mcontext->__ss.__fp; + *bp = AARCH64_GET_REG(fp); # else - *bp = ucontext->uc_mcontext->__ss.__lr; + *bp = AARCH64_GET_REG(lr); # endif - *sp = ucontext->uc_mcontext->__ss.__sp; + *sp = AARCH64_GET_REG(sp); # elif defined(__x86_64__) *pc = ucontext->uc_mcontext->__ss.__rip; *bp = ucontext->uc_mcontext->__ss.__rbp; @@ -787,16 +868,34 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { # endif } -void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } +void SignalContext::InitPcSpBp() { + addr = (uptr)ptrauth_strip((void *)addr, 0); + GetPcSpBp(context, &pc, &sp, &bp); +} + +// ASan/TSan use mmap in a way that creates “deallocation gaps” which triggers +// EXC_GUARD exceptions on macOS 10.15+ (XNU 19.0+). +static void DisableMmapExcGuardExceptions() { + using task_exc_guard_behavior_t = uint32_t; + using task_set_exc_guard_behavior_t = + kern_return_t(task_t task, task_exc_guard_behavior_t behavior); + auto *set_behavior = (task_set_exc_guard_behavior_t *)dlsym( + RTLD_DEFAULT, "task_set_exc_guard_behavior"); + if (set_behavior == nullptr) return; + const task_exc_guard_behavior_t task_exc_guard_none = 0; + set_behavior(mach_task_self(), task_exc_guard_none); +} void InitializePlatformEarly() { - // Only use xnu_fast_mmap when on x86_64 and the OS supports it. + // Only use xnu_fast_mmap when on x86_64 and the kernel supports it. use_xnu_fast_mmap = #if defined(__x86_64__) - GetMacosVersion() >= MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4; + GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5); #else false; #endif + if (GetDarwinKernelVersion() >= DarwinKernelVersion(19, 0)) + DisableMmapExcGuardExceptions(); } #if !SANITIZER_GO @@ -837,20 +936,10 @@ bool ReexecDisabled() { return false; } -extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber; -static const double kMinDyldVersionWithAutoInterposition = 360.0; - -bool DyldNeedsEnvVariable() { - // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users - // still may want use them on older systems. On older Darwin platforms, dyld - // doesn't export dyldVersionNumber symbol and we simply return true. - if (!&dyldVersionNumber) return true; +static bool DyldNeedsEnvVariable() { // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if - // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via - // GetMacosVersion() doesn't work for the simulator. Let's instead check - // `dyldVersionNumber`, which is exported by dyld, against a known version - // number from the first OS release where this appeared. - return dyldVersionNumber < kMinDyldVersionWithAutoInterposition; + // DYLD_INSERT_LIBRARIES is not set. + return GetMacosAlignedVersion() < MacosVersion(10, 11); } void MaybeReexec() { @@ -996,7 +1085,7 @@ char **GetArgv() { return *_NSGetArgv(); } -#if SANITIZER_IOS +#if SANITIZER_IOS && !SANITIZER_IOSSIM // The task_vm_info struct is normally provided by the macOS SDK, but we need // fields only available in 10.12+. Declare the struct manually to be able to // build against older SDKs. @@ -1063,6 +1152,53 @@ uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); } +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, uptr &high_mem_end) { + const uptr granularity = GetMmapGranularity(); + const uptr alignment = + Max(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); + const uptr left_padding = + Max(granularity, 1ULL << min_shadow_base_alignment); + + uptr space_size = shadow_size_bytes + left_padding; + + uptr largest_gap_found = 0; + uptr max_occupied_addr = 0; + VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); + uptr shadow_start = + FindAvailableMemoryRange(space_size, alignment, granularity, + &largest_gap_found, &max_occupied_addr); + // If the shadow doesn't fit, restrict the address space to make it fit. + if (shadow_start == 0) { + VReport( + 2, + "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n", + largest_gap_found, max_occupied_addr); + uptr new_max_vm = RoundDownTo(largest_gap_found << shadow_scale, alignment); + if (new_max_vm < max_occupied_addr) { + Report("Unable to find a memory range for dynamic shadow.\n"); + Report( + "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, " + "new_max_vm = %p\n", + space_size, largest_gap_found, max_occupied_addr, new_max_vm); + CHECK(0 && "cannot place shadow"); + } + RestrictMemoryToMaxAddress(new_max_vm); + high_mem_end = new_max_vm - 1; + space_size = (high_mem_end >> shadow_scale) + left_padding; + VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); + shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity, + nullptr, nullptr); + if (shadow_start == 0) { + Report("Unable to find a memory range after restricting VM.\n"); + CHECK(0 && "cannot place shadow after restricting vm"); + } + } + CHECK_NE((uptr)0, shadow_start); + CHECK(IsAligned(shadow_start, alignment)); + return shadow_start; +} + uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, uptr *largest_gap_found, uptr *max_occupied_addr) { @@ -1123,6 +1259,8 @@ void SignalContext::DumpAllRegisters(void *context) { ucontext_t *ucontext = (ucontext_t*)context; # define DUMPREG64(r) \ Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r); +# define DUMPREGA64(r) \ + Printf(" %s = 0x%016llx ", #r, AARCH64_GET_REG(r)); # define DUMPREG32(r) \ Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r); # define DUMPREG_(r) Printf(" "); DUMPREG(r); @@ -1148,7 +1286,7 @@ void SignalContext::DumpAllRegisters(void *context) { DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n"); DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n"); DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n"); - DUMPREG(x[28]); DUMPREG___(fp); DUMPREG___(lr); DUMPREG___(sp); Printf("\n"); + DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n"); # elif defined(__arm__) # define DUMPREG(r) DUMPREG32(r) DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n"); @@ -1181,7 +1319,7 @@ void FormatUUID(char *out, uptr size, const u8 *uuid) { uuid[12], uuid[13], uuid[14], uuid[15]); } -void PrintModuleMap() { +void DumpProcessMap() { Printf("Process module map:\n"); MemoryMappingLayout memory_mapping(false); InternalMmapVector modules; @@ -1214,6 +1352,8 @@ u32 GetNumberOfCPUs() { return (u32)sysconf(_SC_NPROCESSORS_ONLN); } +void InitializePlatformCommonFlags(CommonFlags *cf) {} + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h index 2257883084ea9..023071e4f11de 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h @@ -30,25 +30,33 @@ struct MemoryMappingLayoutData { bool current_instrumented; }; -enum MacosVersion { - MACOS_VERSION_UNINITIALIZED = 0, - MACOS_VERSION_UNKNOWN, - MACOS_VERSION_LEOPARD, - MACOS_VERSION_SNOW_LEOPARD, - MACOS_VERSION_LION, - MACOS_VERSION_MOUNTAIN_LION, - MACOS_VERSION_MAVERICKS, - MACOS_VERSION_YOSEMITE, - MACOS_VERSION_EL_CAPITAN, - MACOS_VERSION_SIERRA, - MACOS_VERSION_HIGH_SIERRA, - MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4, - MACOS_VERSION_MOJAVE, - MACOS_VERSION_CATALINA, - MACOS_VERSION_UNKNOWN_NEWER +template +struct VersionBase { + u16 major; + u16 minor; + + VersionBase(u16 major, u16 minor) : major(major), minor(minor) {} + + bool operator==(const VersionType &other) const { + return major == other.major && minor == other.minor; + } + bool operator>=(const VersionType &other) const { + return major > other.major || + (major == other.major && minor >= other.minor); + } + bool operator<(const VersionType &other) const { return !(*this >= other); } +}; + +struct MacosVersion : VersionBase { + MacosVersion(u16 major, u16 minor) : VersionBase(major, minor) {} +}; + +struct DarwinKernelVersion : VersionBase { + DarwinKernelVersion(u16 major, u16 minor) : VersionBase(major, minor) {} }; -MacosVersion GetMacosVersion(); +MacosVersion GetMacosAlignedVersion(); +DarwinKernelVersion GetDarwinKernelVersion(); char **GetEnviron(); @@ -67,7 +75,7 @@ asm(".desc ___crashreporter_info__, 0x10"); namespace __sanitizer { static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED); -INLINE void CRAppendCrashLogMessage(const char *msg) { +inline void CRAppendCrashLogMessage(const char *msg) { BlockingMutexLock l(&crashreporter_info_mutex); internal_strlcat(__crashreporter_info_buff__, msg, sizeof(__crashreporter_info_buff__)); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc index 11adbe5c25b4b..647bcdfe105e6 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc @@ -61,12 +61,10 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone, malloc_zone_t *new_zone = (malloc_zone_t *)p; internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone)); new_zone->zone_name = NULL; // The name will be changed anyway. - if (GetMacosVersion() >= MACOS_VERSION_LION) { - // Prevent the client app from overwriting the zone contents. - // Library functions that need to modify the zone will set PROT_WRITE on it. - // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher. - mprotect(new_zone, allocated_size, PROT_READ); - } + // Prevent the client app from overwriting the zone contents. + // Library functions that need to modify the zone will set PROT_WRITE on it. + // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher. + mprotect(new_zone, allocated_size, PROT_READ); // We're explicitly *NOT* registering the zone. return new_zone; } @@ -75,11 +73,9 @@ INTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) { COMMON_MALLOC_ENTER(); // We don't need to do anything here. We're not registering new zones, so we // don't to unregister. Just un-mprotect and free() the zone. - if (GetMacosVersion() >= MACOS_VERSION_LION) { - uptr page_size = GetPageSizeCached(); - uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size); - mprotect(zone, allocated_size, PROT_READ | PROT_WRITE); - } + uptr page_size = GetPageSizeCached(); + uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size); + mprotect(zone, allocated_size, PROT_READ | PROT_WRITE); if (zone->zone_name) { COMMON_MALLOC_FREE((void *)zone->zone_name); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp index 49a951e04b374..98ac7365da051 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp @@ -110,6 +110,11 @@ int internal_mprotect(void *addr, uptr length, int prot) { return _REAL(mprotect, addr, length, prot); } +int internal_madvise(uptr addr, uptr length, int advice) { + DEFINE__REAL(int, madvise, void *a, uptr b, int c); + return _REAL(madvise, (void *)addr, length, advice); +} + uptr internal_close(fd_t fd) { CHECK(&_sys_close); return _sys_close(fd); @@ -265,6 +270,11 @@ uptr internal_getppid() { return _REAL(getppid); } +int internal_dlinfo(void *handle, int request, void *p) { + DEFINE__REAL(int, dlinfo, void *a, int b, void *c); + return _REAL(dlinfo, handle, request, p); +} + uptr internal_getdents(fd_t fd, void *dirp, unsigned int count) { DEFINE__REAL(int, __getdents30, int a, void *b, size_t c); return _REAL(__getdents30, fd, dirp, count); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_openbsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_openbsd.cpp index ed2d8edeb7a2c..e69de29bb2d1d 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_openbsd.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_openbsd.cpp @@ -1,115 +0,0 @@ -//===-- sanitizer_openbsd.cpp ---------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is shared between various sanitizers' runtime libraries and -// implements Solaris-specific functions. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_OPENBSD - -#include - -#include "sanitizer_common.h" -#include "sanitizer_flags.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_libc.h" -#include "sanitizer_placement_new.h" -#include "sanitizer_platform_limits_posix.h" -#include "sanitizer_procmaps.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern char **environ; - -namespace __sanitizer { - -uptr internal_mmap(void *addr, size_t length, int prot, int flags, int fd, - u64 offset) { - return (uptr)mmap(addr, length, prot, flags, fd, offset); -} - -uptr internal_munmap(void *addr, uptr length) { return munmap(addr, length); } - -int internal_mprotect(void *addr, uptr length, int prot) { - return mprotect(addr, length, prot); -} - -int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, - const void *newp, uptr newlen) { - Printf("internal_sysctlbyname not implemented for OpenBSD"); - Die(); - return 0; -} - -uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { - // On OpenBSD we cannot get the full path - struct kinfo_proc kp; - uptr kl; - const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()}; - if (internal_sysctl(Mib, ARRAY_SIZE(Mib), &kp, &kl, NULL, 0) != -1) - return internal_snprintf(buf, - (KI_MAXCOMLEN < buf_len ? KI_MAXCOMLEN : buf_len), - "%s", kp.p_comm); - return (uptr)0; -} - -static void GetArgsAndEnv(char ***argv, char ***envp) { - uptr nargv; - uptr nenv; - int argvmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV}; - int envmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ENV}; - if (internal_sysctl(argvmib, 4, NULL, &nargv, NULL, 0) == -1) { - Printf("sysctl KERN_PROC_NARGV failed\n"); - Die(); - } - if (internal_sysctl(envmib, 4, NULL, &nenv, NULL, 0) == -1) { - Printf("sysctl KERN_PROC_NENV failed\n"); - Die(); - } - if (internal_sysctl(argvmib, 4, &argv, &nargv, NULL, 0) == -1) { - Printf("sysctl KERN_PROC_ARGV failed\n"); - Die(); - } - if (internal_sysctl(envmib, 4, &envp, &nenv, NULL, 0) == -1) { - Printf("sysctl KERN_PROC_ENV failed\n"); - Die(); - } -} - -char **GetArgv() { - char **argv, **envp; - GetArgsAndEnv(&argv, &envp); - return argv; -} - -char **GetEnviron() { - char **argv, **envp; - GetArgsAndEnv(&argv, &envp); - return envp; -} - -void ReExec() { - UNIMPLEMENTED(); -} - -} // namespace __sanitizer - -#endif // SANITIZER_OPENBSD diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h index 6d098e3a78269..79cb5a2a5deec 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h @@ -13,18 +13,31 @@ #define SANITIZER_PLATFORM_H #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ - !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(_WIN32) && \ + !defined(__APPLE__) && !defined(_WIN32) && \ !defined(__Fuchsia__) && !defined(__rtems__) && \ !(defined(__sun__) && defined(__svr4__)) && !defined(__EMSCRIPTEN__) # error "This operating system is not supported" #endif +// Get __GLIBC__ on a glibc platform. Exclude Android: features.h includes C +// function declarations into a .S file which doesn't compile. +// https://crbug.com/1162741 +#if __has_include() && !defined(__ANDROID__) +#include +#endif + #if defined(__linux__) # define SANITIZER_LINUX 1 #else # define SANITIZER_LINUX 0 #endif +#if defined(__GLIBC__) +# define SANITIZER_GLIBC 1 +#else +# define SANITIZER_GLIBC 0 +#endif + #if defined(__FreeBSD__) # define SANITIZER_FREEBSD 1 #else @@ -37,12 +50,6 @@ # define SANITIZER_NETBSD 0 #endif -#if defined(__OpenBSD__) -# define SANITIZER_OPENBSD 1 -#else -# define SANITIZER_OPENBSD 0 -#endif - #if defined(__sun__) && defined(__svr4__) # define SANITIZER_SOLARIS 1 #else @@ -118,8 +125,7 @@ #define SANITIZER_POSIX \ (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ - SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_SOLARIS || \ - SANITIZER_EMSCRIPTEN) + SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN) #if __LP64__ || defined(_WIN64) # define SANITIZER_WORDSIZE 64 @@ -139,6 +145,12 @@ # define SANITIZER_X32 0 #endif +#if defined(__i386__) || defined(_M_IX86) +# define SANITIZER_I386 1 +#else +# define SANITIZER_I386 0 +#endif + #if defined(__mips__) # define SANITIZER_MIPS 1 # if defined(__mips64) @@ -220,6 +232,12 @@ # define SANITIZER_MYRIAD2 0 #endif +#if defined(__riscv) && (__riscv_xlen == 64) +#define SANITIZER_RISCV64 1 +#else +#define SANITIZER_RISCV64 0 +#endif + // By default we allow to use SizeClassAllocator64 on 64-bit platform. // But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64 // does not work well and we need to fallback to SizeClassAllocator32. @@ -239,7 +257,13 @@ // FIXME: this value should be different on different platforms. Larger values // will still work but will consume more memory for TwoLevelByteMap. #if defined(__mips__) +#if SANITIZER_GO && defined(__mips64) +#define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47) +#else # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40) +#endif +#elif SANITIZER_RISCV64 +#define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 38) #elif defined(__aarch64__) # if SANITIZER_MAC // Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM @@ -332,7 +356,7 @@ #endif #if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS + SANITIZER_SOLARIS # define SANITIZER_MADVISE_DONTNEED MADV_FREE #else # define SANITIZER_MADVISE_DONTNEED MADV_DONTNEED diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 658259830f3d1..ee08024e06987 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -15,127 +15,127 @@ #include "sanitizer_glibc_version.h" #include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" #if SANITIZER_POSIX -# define SI_POSIX 1 +#define SI_POSIX 1 #else -# define SI_POSIX 0 +#define SI_POSIX 0 #endif #if !SANITIZER_WINDOWS -# define SI_WINDOWS 0 +#define SI_WINDOWS 0 #else -# define SI_WINDOWS 1 +#define SI_WINDOWS 1 #endif #if SI_WINDOWS && SI_POSIX -# error "Windows is not POSIX!" +#error "Windows is not POSIX!" #endif #if SI_POSIX -# include "sanitizer_platform_limits_freebsd.h" -# include "sanitizer_platform_limits_netbsd.h" -# include "sanitizer_platform_limits_openbsd.h" -# include "sanitizer_platform_limits_posix.h" -# include "sanitizer_platform_limits_solaris.h" +#include "sanitizer_platform_limits_freebsd.h" +#include "sanitizer_platform_limits_netbsd.h" +#include "sanitizer_platform_limits_posix.h" +#include "sanitizer_platform_limits_solaris.h" #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID -# define SI_LINUX_NOT_ANDROID 1 +#define SI_LINUX_NOT_ANDROID 1 #else -# define SI_LINUX_NOT_ANDROID 0 +#define SI_LINUX_NOT_ANDROID 0 #endif -#if SANITIZER_ANDROID -# define SI_ANDROID 1 +#if SANITIZER_GLIBC +#define SI_GLIBC 1 #else -# define SI_ANDROID 0 +#define SI_GLIBC 0 #endif -#if SANITIZER_FREEBSD -# define SI_FREEBSD 1 +#if SANITIZER_ANDROID +#define SI_ANDROID 1 #else -# define SI_FREEBSD 0 +#define SI_ANDROID 0 #endif -#if SANITIZER_NETBSD -# define SI_NETBSD 1 +#if SANITIZER_FREEBSD +#define SI_FREEBSD 1 #else -# define SI_NETBSD 0 +#define SI_FREEBSD 0 #endif -#if SANITIZER_OPENBSD -#define SI_OPENBSD 1 +#if SANITIZER_NETBSD +#define SI_NETBSD 1 #else -#define SI_OPENBSD 0 +#define SI_NETBSD 0 #endif #if SANITIZER_LINUX -# define SI_LINUX 1 +#define SI_LINUX 1 #else -# define SI_LINUX 0 +#define SI_LINUX 0 #endif #if SANITIZER_MAC -# define SI_MAC 1 -# define SI_NOT_MAC 0 +#define SI_MAC 1 +#define SI_NOT_MAC 0 #else -# define SI_MAC 0 -# define SI_NOT_MAC 1 +#define SI_MAC 0 +#define SI_NOT_MAC 1 #endif #if SANITIZER_IOS -# define SI_IOS 1 +#define SI_IOS 1 #else -# define SI_IOS 0 +#define SI_IOS 0 #endif #if SANITIZER_IOSSIM -# define SI_IOSSIM 1 +#define SI_IOSSIM 1 #else -# define SI_IOSSIM 0 +#define SI_IOSSIM 0 #endif #if SANITIZER_WATCHOS -# define SI_WATCHOS 1 +#define SI_WATCHOS 1 #else -# define SI_WATCHOS 0 +#define SI_WATCHOS 0 #endif #if SANITIZER_TVOS -# define SI_TVOS 1 +#define SI_TVOS 1 #else -# define SI_TVOS 0 +#define SI_TVOS 0 #endif #if SANITIZER_FUCHSIA -# define SI_NOT_FUCHSIA 0 +#define SI_NOT_FUCHSIA 0 #else -# define SI_NOT_FUCHSIA 1 +#define SI_NOT_FUCHSIA 1 #endif #if SANITIZER_RTEMS -# define SI_NOT_RTEMS 0 +#define SI_NOT_RTEMS 0 #else -# define SI_NOT_RTEMS 1 +#define SI_NOT_RTEMS 1 #endif #if SANITIZER_SOLARIS -# define SI_SOLARIS 1 +#define SI_SOLARIS 1 #else -# define SI_SOLARIS 0 +#define SI_SOLARIS 0 #endif #if SANITIZER_SOLARIS32 -# define SI_SOLARIS32 1 +#define SI_SOLARIS32 1 #else -# define SI_SOLARIS32 0 +#define SI_SOLARIS32 0 #endif #if SANITIZER_POSIX && !SANITIZER_MAC -# define SI_POSIX_NOT_MAC 1 +#define SI_POSIX_NOT_MAC 1 #else -# define SI_POSIX_NOT_MAC 0 +#define SI_POSIX_NOT_MAC 0 #endif #if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN @@ -145,9 +145,9 @@ #endif #if SANITIZER_LINUX && !SANITIZER_FREEBSD -# define SI_LINUX_NOT_FREEBSD 1 -# else -# define SI_LINUX_NOT_FREEBSD 0 +#define SI_LINUX_NOT_FREEBSD 1 +#else +#define SI_LINUX_NOT_FREEBSD 0 #endif #if SANITIZER_EMSCRIPTEN @@ -175,21 +175,20 @@ #define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_BCMP \ SANITIZER_INTERCEPT_MEMCMP && \ - ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_OPENBSD || SI_FREEBSD) + ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_STRNDUP SI_POSIX -#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD +#define SANITIZER_INTERCEPT___STRNDUP SI_GLIBC #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 -# define SI_MAC_DEPLOYMENT_BELOW_10_7 1 +#define SI_MAC_DEPLOYMENT_BELOW_10_7 1 #else -# define SI_MAC_DEPLOYMENT_BELOW_10_7 0 +#define SI_MAC_DEPLOYMENT_BELOW_10_7 0 #endif // memmem on Darwin doesn't exist on 10.6 // FIXME: enable memmem on Windows. #define SANITIZER_INTERCEPT_MEMMEM (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_7) #define SANITIZER_INTERCEPT_MEMCHR SI_NOT_FUCHSIA -#define SANITIZER_INTERCEPT_MEMRCHR \ - (SI_FREEBSD || SI_LINUX || SI_NETBSD || SI_OPENBSD) +#define SANITIZER_INTERCEPT_MEMRCHR (SI_FREEBSD || SI_LINUX || SI_NETBSD) #define SANITIZER_INTERCEPT_READ SI_POSIX #define SANITIZER_INTERCEPT_PREAD SI_POSIX @@ -202,63 +201,60 @@ #define SANITIZER_INTERCEPT_FPUTS SI_POSIX #define SANITIZER_INTERCEPT_PUTS SI_POSIX -#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 -#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 +#define SANITIZER_INTERCEPT_PREAD64 (SI_GLIBC || SI_SOLARIS32) +#define SANITIZER_INTERCEPT_PWRITE64 (SI_GLIBC || SI_SOLARIS32) #define SANITIZER_INTERCEPT_READV SI_POSIX #define SANITIZER_INTERCEPT_WRITEV SI_POSIX #define SANITIZER_INTERCEPT_PREADV \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID) + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PREADV64 SI_GLIBC +#define SANITIZER_INTERCEPT_PWRITEV64 SI_GLIBC -#define SANITIZER_INTERCEPT_PRCTL SI_LINUX +#define SANITIZER_INTERCEPT_PRCTL SI_LINUX #define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_POSIX #define SANITIZER_INTERCEPT_STRPTIME SI_POSIX #define SANITIZER_INTERCEPT_SCANF SI_POSIX -#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC #ifndef SANITIZER_INTERCEPT_PRINTF -# define SANITIZER_INTERCEPT_PRINTF SI_POSIX -# define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD) -# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PRINTF SI_POSIX +#define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD) +#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC #endif #define SANITIZER_INTERCEPT___PRINTF_CHK \ - (SANITIZER_INTERCEPT_PRINTF && SI_LINUX_NOT_ANDROID) + (SANITIZER_INTERCEPT_PRINTF && SI_GLIBC) #define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX -#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ - SI_SOLARIS) -#define SANITIZER_INTERCEPT_GETPWENT \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ - SI_SOLARIS) -#define SANITIZER_INTERCEPT_FGETGRENT_R \ - (SI_FREEBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETPWENT \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_FGETGRENT_R (SI_GLIBC || SI_SOLARIS) #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_GETPWENT_R \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) -#define SANITIZER_INTERCEPT_FGETPWENT_R \ - (SI_FREEBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_FGETPWENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS) #define SANITIZER_INTERCEPT_SETPWENT \ (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_CLOCK_GETTIME \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX || SI_SOLARIS) + (SI_FREEBSD || SI_NETBSD || SI_LINUX || SI_SOLARIS) +#define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID SI_LINUX #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX #define SANITIZER_INTERCEPT_TIME SI_POSIX -#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID || SI_SOLARIS -#define SANITIZER_INTERCEPT_GLOB64 SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC #define SANITIZER_INTERCEPT_WAIT SI_POSIX #define SANITIZER_INTERCEPT_INET SI_POSIX -#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM (SI_POSIX && !SI_OPENBSD) +#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX #define SANITIZER_INTERCEPT_GETADDRINFO SI_POSIX #define SANITIZER_INTERCEPT_GETNAMEINFO SI_POSIX #define SANITIZER_INTERCEPT_GETSOCKNAME SI_POSIX @@ -270,28 +266,27 @@ (SI_FREEBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_GETHOSTBYADDR_R \ (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) -#define SANITIZER_INTERCEPT_GETHOSTENT_R \ - (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS) #define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX #define SANITIZER_INTERCEPT_ACCEPT SI_POSIX -#define SANITIZER_INTERCEPT_ACCEPT4 \ - (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_OPENBSD) +#define SANITIZER_INTERCEPT_ACCEPT4 (SI_LINUX_NOT_ANDROID || SI_NETBSD) #define SANITIZER_INTERCEPT_PACCEPT SI_NETBSD #define SANITIZER_INTERCEPT_MODF SI_POSIX #define SANITIZER_INTERCEPT_RECVMSG SI_POSIX #define SANITIZER_INTERCEPT_SENDMSG SI_POSIX #define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX #define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX +#define SANITIZER_INTERCEPT_SYSMSG SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX #define SANITIZER_INTERCEPT_IOCTL SI_POSIX && !SI_EMSCRIPTEN #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX #define SANITIZER_INTERCEPT_READDIR SI_POSIX #define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 -#if SI_LINUX_NOT_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__)) +#if SI_LINUX_NOT_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__) || SANITIZER_RISCV64) #define SANITIZER_INTERCEPT_PTRACE 1 #else #define SANITIZER_INTERCEPT_PTRACE 0 @@ -308,72 +303,68 @@ #define SANITIZER_INTERCEPT___STRXFRM_L SI_LINUX #define SANITIZER_INTERCEPT_WCSXFRM SI_POSIX #define SANITIZER_INTERCEPT___WCSXFRM_L SI_LINUX -#define SANITIZER_INTERCEPT_WCSNRTOMBS \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ - SI_SOLARIS) -#define SANITIZER_INTERCEPT_WCRTOMB \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ - SI_SOLARIS) -#define SANITIZER_INTERCEPT_WCTOMB \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ - SI_SOLARIS) +#define SANITIZER_INTERCEPT_WCSNRTOMBS \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_WCRTOMB \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_WCTOMB \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_REALPATH SI_POSIX -#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME \ - (SI_LINUX_NOT_ANDROID || SI_SOLARIS) -#define SANITIZER_INTERCEPT_CONFSTR \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ - SI_SOLARIS) +#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME (SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_CONFSTR \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_STRERROR SI_POSIX_NOT_EMSCRIPTEN #define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCANDIR \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 #define SANITIZER_INTERCEPT_GETGROUPS SI_POSIX #define SANITIZER_INTERCEPT_POLL SI_POSIX #define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID || SI_SOLARIS -#define SANITIZER_INTERCEPT_WORDEXP \ +#define SANITIZER_INTERCEPT_WORDEXP \ (SI_FREEBSD || SI_NETBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID || \ - SI_SOLARIS) + SI_SOLARIS) // NOLINT #define SANITIZER_INTERCEPT_SIGWAIT SI_POSIX #define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_SIGSETOPS \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) +#define SANITIZER_INTERCEPT_SIGSET_LOGICOPS SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGPENDING SI_POSIX #define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX #define SANITIZER_INTERCEPT_BACKTRACE \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS) #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATFS \ (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_STATFS64 \ - ((SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID) + (((SI_MAC && !TARGET_CPU_ARM64) && !SI_IOS) || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_STATVFS \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID) + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_INITGROUPS SI_POSIX -#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON (SI_POSIX && !SI_OPENBSD) +#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_POSIX #define SANITIZER_INTERCEPT_ETHER_HOST \ (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_ETHER_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID) #define SANITIZER_INTERCEPT_SHMCTL \ (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \ - SI_NETBSD || SI_OPENBSD || SI_SOLARIS) // NOLINT -#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID + SI_NETBSD || SI_SOLARIS) // NOLINT +#define SANITIZER_INTERCEPT_RANDOM_R SI_GLIBC #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) -#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED (SI_POSIX && !SI_OPENBSD) +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_GLIBC +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED \ - (SI_POSIX && !SI_NETBSD && !SI_OPENBSD) -#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE (SI_POSIX && !SI_OPENBSD) + (SI_POSIX && !SI_NETBSD) +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_POSIX #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \ (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ @@ -382,17 +373,18 @@ (SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED \ - (SI_POSIX && !SI_NETBSD && !SI_OPENBSD) -#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED \ - (SI_POSIX && !SI_NETBSD && !SI_OPENBSD) + (SI_POSIX && !SI_NETBSD) +#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_GLIBC +#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED (SI_POSIX && !SI_NETBSD) #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK \ (SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED \ - (SI_LINUX_NOT_ANDROID && !SI_NETBSD && !SI_OPENBSD) + (SI_LINUX_NOT_ANDROID && !SI_NETBSD) #define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD #define SANITIZER_INTERCEPT_TMPNAM SI_POSIX -#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_TMPNAM_R (SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_PTSNAME SI_LINUX +#define SANITIZER_INTERCEPT_PTSNAME_R SI_LINUX #define SANITIZER_INTERCEPT_TTYNAME SI_POSIX #define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX #define SANITIZER_INTERCEPT_TEMPNAM SI_POSIX @@ -403,71 +395,67 @@ #define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD) #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS) #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS -#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_RAND_R \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \ - SI_SOLARIS) +#define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC +#define SANITIZER_INTERCEPT_RAND_R \ + (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_ICONV \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_TIMES SI_POSIX // FIXME: getline seems to be available on OSX 10.7 #define SANITIZER_INTERCEPT_GETLINE \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT__EXIT \ - (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_SOLARIS) + (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC || SI_SOLARIS) #define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX -#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_GLIBC #define SANITIZER_INTERCEPT___LIBC_MUTEX SI_NETBSD #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS) #define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \ - (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) + (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS) #define SANITIZER_INTERCEPT_TLS_GET_ADDR \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX #define SANITIZER_INTERCEPT_GETXATTR SI_LINUX #define SANITIZER_INTERCEPT_GETRESID SI_LINUX -#define SANITIZER_INTERCEPT_GETIFADDRS \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \ - SI_SOLARIS) -#define SANITIZER_INTERCEPT_IF_INDEXTONAME \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \ - SI_SOLARIS) +#define SANITIZER_INTERCEPT_GETIFADDRS \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_IF_INDEXTONAME \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS) #define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID #if SI_LINUX && defined(__arm__) #define SANITIZER_INTERCEPT_AEABI_MEM 1 #else #define SANITIZER_INTERCEPT_AEABI_MEM 0 #endif -#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_GLIBC #define SANITIZER_INTERCEPT_BZERO SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_FTIME \ - (!SI_FREEBSD && !SI_NETBSD && !SI_OPENBSD && SI_POSIX) -#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS +#define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX) +#define SANITIZER_INTERCEPT_XDR (SI_GLIBC || SI_SOLARIS) +#define SANITIZER_INTERCEPT_XDRREC SI_GLIBC #define SANITIZER_INTERCEPT_TSEARCH \ - (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) -#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID + (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_GLIBC #define SANITIZER_INTERCEPT_FOPEN SI_POSIX -#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32 +#define SANITIZER_INTERCEPT_FOPEN64 (SI_GLIBC || SI_SOLARIS32) #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM \ - (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) -#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID + (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_OBSTACK SI_GLIBC #define SANITIZER_INTERCEPT_FFLUSH SI_POSIX #define SANITIZER_INTERCEPT_FCLOSE SI_POSIX #ifndef SANITIZER_INTERCEPT_DLOPEN_DLCLOSE -#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \ - (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \ - SI_SOLARIS) +#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS) #endif #define SANITIZER_INTERCEPT_GETPASS \ - (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD) + (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD) #define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_MLOCKX SI_POSIX @@ -475,21 +463,20 @@ #define SANITIZER_INTERCEPT_SEM \ (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_SOLARIS) #define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_POSIX -#define SANITIZER_INTERCEPT_MINCORE \ - (SI_LINUX || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) +#define SANITIZER_INTERCEPT_MINCORE (SI_LINUX || SI_NETBSD || SI_SOLARIS) #define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX #define SANITIZER_INTERCEPT_CTERMID \ - (SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) + (SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_SOLARIS) #define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD || SI_SOLARIS) #define SANITIZER_INTERCEPTOR_HOOKS \ - (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD) + (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD || SI_SOLARIS) #define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX #define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX #define SANITIZER_INTERCEPT_STAT \ - (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_OPENBSD || SI_SOLARIS) + (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_SOLARIS) #define SANITIZER_INTERCEPT_LSTAT (SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT___XSTAT (!SANITIZER_INTERCEPT_STAT && SI_POSIX) #define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID @@ -502,41 +489,35 @@ (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD) #define SANITIZER_INTERCEPT_GETLOADAVG \ - (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_OPENBSD) + (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD) #define SANITIZER_INTERCEPT_MMAP SI_POSIX #define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \ - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ - SI_NOT_RTEMS) +#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID) #define SANITIZER_INTERCEPT_MEMALIGN \ - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_RTEMS) -#define SANITIZER_INTERCEPT_PVALLOC \ - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ - SI_NOT_RTEMS) -#define SANITIZER_INTERCEPT_CFREE \ - (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \ - SI_NOT_RTEMS) + (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_RTEMS) +#define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC +#define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID) +#define SANITIZER_INTERCEPT_CFREE SI_GLIBC #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS) -#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE \ - (!SI_MAC && !SI_OPENBSD && !SI_NETBSD) +#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX #define SANITIZER_INTERCEPT_WCSDUP SI_POSIX #define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA) #define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID -#define SANITIZER_INTERCEPT_ACCT (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_ACCT (SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_USER_FROM_UID SI_NETBSD #define SANITIZER_INTERCEPT_UID_FROM_USER SI_NETBSD #define SANITIZER_INTERCEPT_GROUP_FROM_GID SI_NETBSD #define SANITIZER_INTERCEPT_GID_FROM_GROUP SI_NETBSD -#define SANITIZER_INTERCEPT_ACCESS (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) -#define SANITIZER_INTERCEPT_FACCESSAT (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) -#define SANITIZER_INTERCEPT_GETGROUPLIST (SI_NETBSD || SI_OPENBSD) -#define SANITIZER_INTERCEPT_STRLCPY \ - (SI_NETBSD || SI_FREEBSD || SI_OPENBSD || SI_MAC || SI_ANDROID) +#define SANITIZER_INTERCEPT_ACCESS (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_FACCESSAT (SI_NETBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_GETGROUPLIST SI_NETBSD +#define SANITIZER_INTERCEPT_STRLCPY \ + (SI_NETBSD || SI_FREEBSD || SI_MAC || SI_ANDROID) #define SANITIZER_INTERCEPT_NAME_TO_HANDLE_AT SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_OPEN_BY_HANDLE_AT SI_LINUX_NOT_ANDROID @@ -544,22 +525,23 @@ #define SANITIZER_INTERCEPT_READLINK SI_POSIX #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101000 -# define SI_MAC_DEPLOYMENT_BELOW_10_10 1 +#define SI_MAC_DEPLOYMENT_BELOW_10_10 1 #else -# define SI_MAC_DEPLOYMENT_BELOW_10_10 0 +#define SI_MAC_DEPLOYMENT_BELOW_10_10 0 #endif #define SANITIZER_INTERCEPT_READLINKAT \ (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_10) -#define SANITIZER_INTERCEPT_DEVNAME (SI_NETBSD || SI_OPENBSD || SI_FREEBSD) +#define SANITIZER_INTERCEPT_DEVNAME (SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_DEVNAME_R (SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_FGETLN (SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_TTYENT SI_NETBSD -#define SANITIZER_INTERCEPT_PROTOENT SI_NETBSD +#define SANITIZER_INTERCEPT_PROTOENT (SI_NETBSD || SI_LINUX) +#define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC #define SANITIZER_INTERCEPT_NETENT SI_NETBSD -#define SANITIZER_INTERCEPT_SETVBUF (SI_NETBSD || SI_FREEBSD || \ - SI_LINUX || SI_MAC) +#define SANITIZER_INTERCEPT_SETVBUF \ + (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC) #define SANITIZER_INTERCEPT_GETMNTINFO (SI_NETBSD || SI_FREEBSD || SI_MAC) #define SANITIZER_INTERCEPT_MI_VECTOR_HASH SI_NETBSD #define SANITIZER_INTERCEPT_GETVFSSTAT SI_NETBSD @@ -606,7 +588,13 @@ #define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD #define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD #define SANITIZER_INTERCEPT_QSORT \ - (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS) -#define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID) + (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID) +#define SANITIZER_INTERCEPT_QSORT_R SI_GLIBC +// sigaltstack on i386 macOS cannot be intercepted due to setjmp() +// calling it and assuming that it does not clobber registers. +#define SANITIZER_INTERCEPT_SIGALTSTACK \ + (SI_POSIX && !(SANITIZER_MAC && SANITIZER_I386)) +#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD) +#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp index 2d1bb1a12da6e..b1c15be58deaa 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp @@ -15,342 +15,346 @@ #if SANITIZER_FREEBSD +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include +#include +#include +#include +#include +#include +#include +#include +// #include -#include +#include #include +#include +#include #include +#include #include -#include -#include #include #include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include #include -#include #include +#include +#include #define _KERNEL // to declare 'shminfo' structure -# include +#include #undef _KERNEL -#undef INLINE // to avoid clashes with sanitizers' definitions - #undef IOC_DIRMASK -# include -# include -# include - -#include -#include -#include - // Include these after system headers to avoid name clashes and ambiguities. #include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" #include "sanitizer_platform_limits_freebsd.h" namespace __sanitizer { - unsigned struct_cap_rights_sz = sizeof(cap_rights_t); - unsigned struct_utsname_sz = sizeof(struct utsname); - unsigned struct_stat_sz = sizeof(struct stat); - unsigned struct_rusage_sz = sizeof(struct rusage); - unsigned struct_tm_sz = sizeof(struct tm); - unsigned struct_passwd_sz = sizeof(struct passwd); - unsigned struct_group_sz = sizeof(struct group); - unsigned siginfo_t_sz = sizeof(siginfo_t); - unsigned struct_sigaction_sz = sizeof(struct sigaction); - unsigned struct_itimerval_sz = sizeof(struct itimerval); - unsigned pthread_t_sz = sizeof(pthread_t); - unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); - unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); - unsigned pid_t_sz = sizeof(pid_t); - unsigned timeval_sz = sizeof(timeval); - unsigned uid_t_sz = sizeof(uid_t); - unsigned gid_t_sz = sizeof(gid_t); - unsigned fpos_t_sz = sizeof(fpos_t); - unsigned mbstate_t_sz = sizeof(mbstate_t); - unsigned sigset_t_sz = sizeof(sigset_t); - unsigned struct_timezone_sz = sizeof(struct timezone); - unsigned struct_tms_sz = sizeof(struct tms); - unsigned struct_sigevent_sz = sizeof(struct sigevent); - unsigned struct_sched_param_sz = sizeof(struct sched_param); - unsigned struct_statfs_sz = sizeof(struct statfs); - unsigned struct_sockaddr_sz = sizeof(struct sockaddr); - unsigned ucontext_t_sz = sizeof(ucontext_t); - unsigned struct_rlimit_sz = sizeof(struct rlimit); - unsigned struct_timespec_sz = sizeof(struct timespec); - unsigned struct_utimbuf_sz = sizeof(struct utimbuf); - unsigned struct_itimerspec_sz = sizeof(struct itimerspec); - unsigned struct_timeb_sz = sizeof(struct timeb); - unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); - unsigned struct_mq_attr_sz = sizeof(struct mq_attr); - unsigned struct_statvfs_sz = sizeof(struct statvfs); - unsigned struct_shminfo_sz = sizeof(struct shminfo); - unsigned struct_shm_info_sz = sizeof(struct shm_info); - unsigned struct_regmatch_sz = sizeof(regmatch_t); - unsigned struct_regex_sz = sizeof(regex_t); - unsigned struct_fstab_sz = sizeof(struct fstab); - unsigned struct_FTS_sz = sizeof(FTS); - unsigned struct_FTSENT_sz = sizeof(FTSENT); - unsigned struct_StringList_sz = sizeof(StringList); - - const uptr sig_ign = (uptr)SIG_IGN; - const uptr sig_dfl = (uptr)SIG_DFL; - const uptr sig_err = (uptr)SIG_ERR; - const uptr sa_siginfo = (uptr)SA_SIGINFO; - - int shmctl_ipc_stat = (int)IPC_STAT; - int shmctl_ipc_info = (int)IPC_INFO; - int shmctl_shm_info = (int)SHM_INFO; - int shmctl_shm_stat = (int)SHM_STAT; - unsigned struct_utmpx_sz = sizeof(struct utmpx); - - int map_fixed = MAP_FIXED; - - int af_inet = (int)AF_INET; - int af_inet6 = (int)AF_INET6; - - uptr __sanitizer_in_addr_sz(int af) { - if (af == AF_INET) - return sizeof(struct in_addr); - else if (af == AF_INET6) - return sizeof(struct in6_addr); - else - return 0; - } - - unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); - int glob_nomatch = GLOB_NOMATCH; - int glob_altdirfunc = GLOB_ALTDIRFUNC; - - unsigned path_max = PATH_MAX; - - // ioctl arguments - unsigned struct_ifreq_sz = sizeof(struct ifreq); - unsigned struct_termios_sz = sizeof(struct termios); - unsigned struct_winsize_sz = sizeof(struct winsize); +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) { + void *p = nullptr; + return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr; +} + +unsigned struct_cap_rights_sz = sizeof(cap_rights_t); +unsigned struct_utsname_sz = sizeof(struct utsname); +unsigned struct_stat_sz = sizeof(struct stat); +unsigned struct_rusage_sz = sizeof(struct rusage); +unsigned struct_tm_sz = sizeof(struct tm); +unsigned struct_passwd_sz = sizeof(struct passwd); +unsigned struct_group_sz = sizeof(struct group); +unsigned siginfo_t_sz = sizeof(siginfo_t); +unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_stack_t_sz = sizeof(stack_t); +unsigned struct_itimerval_sz = sizeof(struct itimerval); +unsigned pthread_t_sz = sizeof(pthread_t); +unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); +unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); +unsigned pid_t_sz = sizeof(pid_t); +unsigned timeval_sz = sizeof(timeval); +unsigned uid_t_sz = sizeof(uid_t); +unsigned gid_t_sz = sizeof(gid_t); +unsigned fpos_t_sz = sizeof(fpos_t); +unsigned mbstate_t_sz = sizeof(mbstate_t); +unsigned sigset_t_sz = sizeof(sigset_t); +unsigned struct_timezone_sz = sizeof(struct timezone); +unsigned struct_tms_sz = sizeof(struct tms); +unsigned struct_sigevent_sz = sizeof(struct sigevent); +unsigned struct_sched_param_sz = sizeof(struct sched_param); +unsigned struct_statfs_sz = sizeof(struct statfs); +unsigned struct_sockaddr_sz = sizeof(struct sockaddr); +unsigned ucontext_t_sz = sizeof(ucontext_t); +unsigned struct_rlimit_sz = sizeof(struct rlimit); +unsigned struct_timespec_sz = sizeof(struct timespec); +unsigned struct_utimbuf_sz = sizeof(struct utimbuf); +unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +unsigned struct_timeb_sz = sizeof(struct timeb); +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); +unsigned struct_mq_attr_sz = sizeof(struct mq_attr); +unsigned struct_statvfs_sz = sizeof(struct statvfs); +unsigned struct_shminfo_sz = sizeof(struct shminfo); +unsigned struct_shm_info_sz = sizeof(struct shm_info); +unsigned struct_regmatch_sz = sizeof(regmatch_t); +unsigned struct_regex_sz = sizeof(regex_t); +unsigned struct_fstab_sz = sizeof(struct fstab); +unsigned struct_FTS_sz = sizeof(FTS); +unsigned struct_FTSENT_sz = sizeof(FTSENT); +unsigned struct_StringList_sz = sizeof(StringList); + +const uptr sig_ign = (uptr)SIG_IGN; +const uptr sig_dfl = (uptr)SIG_DFL; +const uptr sig_err = (uptr)SIG_ERR; +const uptr sa_siginfo = (uptr)SA_SIGINFO; + +int shmctl_ipc_stat = (int)IPC_STAT; +int shmctl_ipc_info = (int)IPC_INFO; +int shmctl_shm_info = (int)SHM_INFO; +int shmctl_shm_stat = (int)SHM_STAT; +unsigned struct_utmpx_sz = sizeof(struct utmpx); + +int map_fixed = MAP_FIXED; + +int af_inet = (int)AF_INET; +int af_inet6 = (int)AF_INET6; + +uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; +} + +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); +int glob_nomatch = GLOB_NOMATCH; +int glob_altdirfunc = GLOB_ALTDIRFUNC; + +unsigned path_max = PATH_MAX; + +// ioctl arguments +unsigned struct_ifreq_sz = sizeof(struct ifreq); +unsigned struct_termios_sz = sizeof(struct termios); +unsigned struct_winsize_sz = sizeof(struct winsize); #if SOUND_VERSION >= 0x040000 - unsigned struct_copr_buffer_sz = 0; - unsigned struct_copr_debug_buf_sz = 0; - unsigned struct_copr_msg_sz = 0; +unsigned struct_copr_buffer_sz = 0; +unsigned struct_copr_debug_buf_sz = 0; +unsigned struct_copr_msg_sz = 0; #else - unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); - unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); - unsigned struct_copr_msg_sz = sizeof(struct copr_msg); +unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); +unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); +unsigned struct_copr_msg_sz = sizeof(struct copr_msg); #endif - unsigned struct_midi_info_sz = sizeof(struct midi_info); - unsigned struct_mtget_sz = sizeof(struct mtget); - unsigned struct_mtop_sz = sizeof(struct mtop); - unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); - unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); - unsigned struct_synth_info_sz = sizeof(struct synth_info); - unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); - unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); - unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); - unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); - const unsigned long __sanitizer_bufsiz = BUFSIZ; - - const unsigned IOCTL_NOT_PRESENT = 0; - - unsigned IOCTL_FIOASYNC = FIOASYNC; - unsigned IOCTL_FIOCLEX = FIOCLEX; - unsigned IOCTL_FIOGETOWN = FIOGETOWN; - unsigned IOCTL_FIONBIO = FIONBIO; - unsigned IOCTL_FIONCLEX = FIONCLEX; - unsigned IOCTL_FIOSETOWN = FIOSETOWN; - unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; - unsigned IOCTL_SIOCATMARK = SIOCATMARK; - unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; - unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; - unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; - unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; - unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; - unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; - unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; - unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; - unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; - unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; - unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; - unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; - unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; - unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; - unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; - unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; - unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; - unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; - unsigned IOCTL_TIOCCONS = TIOCCONS; - unsigned IOCTL_TIOCEXCL = TIOCEXCL; - unsigned IOCTL_TIOCGETD = TIOCGETD; - unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; - unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; - unsigned IOCTL_TIOCMBIC = TIOCMBIC; - unsigned IOCTL_TIOCMBIS = TIOCMBIS; - unsigned IOCTL_TIOCMGET = TIOCMGET; - unsigned IOCTL_TIOCMSET = TIOCMSET; - unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; - unsigned IOCTL_TIOCNXCL = TIOCNXCL; - unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; - unsigned IOCTL_TIOCPKT = TIOCPKT; - unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; - unsigned IOCTL_TIOCSETD = TIOCSETD; - unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; - unsigned IOCTL_TIOCSTI = TIOCSTI; - unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; - unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; - unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; - unsigned IOCTL_MTIOCGET = MTIOCGET; - unsigned IOCTL_MTIOCTOP = MTIOCTOP; - unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; - unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; - unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; - unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; - unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; - unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; - unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; - unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; - unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; - unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; - unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; - unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; - unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; - unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; - unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; - unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; - unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; - unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; - unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; - unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; - unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; - unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; - unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; - unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; - unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; - unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; - unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; - unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; - unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; - unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; - unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; - unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; - unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; - unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; - unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; - unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; - unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; - unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; - unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; - unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; - unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; - unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; - unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; - unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; - unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; - unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; - unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; - unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; - unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; - unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; - unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; - unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; - unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; - unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; - unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; - unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; - unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; - unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; - unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; - unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; - unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; - unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; - unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; - unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; - unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; - unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; - unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; - unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; - unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; - unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; - unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; - unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; - unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; - unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; - unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; - unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; - unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; - unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; - unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; - unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; - unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; - unsigned IOCTL_VT_GETMODE = VT_GETMODE; - unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; - unsigned IOCTL_VT_RELDISP = VT_RELDISP; - unsigned IOCTL_VT_SETMODE = VT_SETMODE; - unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; - unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; - unsigned IOCTL_KDDISABIO = KDDISABIO; - unsigned IOCTL_KDENABIO = KDENABIO; - unsigned IOCTL_KDGETLED = KDGETLED; - unsigned IOCTL_KDGETMODE = KDGETMODE; - unsigned IOCTL_KDGKBMODE = KDGKBMODE; - unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; - unsigned IOCTL_KDMKTONE = KDMKTONE; - unsigned IOCTL_KDSETLED = KDSETLED; - unsigned IOCTL_KDSETMODE = KDSETMODE; - unsigned IOCTL_KDSKBMODE = KDSKBMODE; - unsigned IOCTL_KIOCSOUND = KIOCSOUND; - unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; - unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; - - const int si_SEGV_MAPERR = SEGV_MAPERR; - const int si_SEGV_ACCERR = SEGV_ACCERR; - const int unvis_valid = UNVIS_VALID; - const int unvis_validpush = UNVIS_VALIDPUSH; -} // namespace __sanitizer +unsigned struct_midi_info_sz = sizeof(struct midi_info); +unsigned struct_mtget_sz = sizeof(struct mtget); +unsigned struct_mtop_sz = sizeof(struct mtop); +unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); +unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); +unsigned struct_synth_info_sz = sizeof(struct synth_info); +unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); +unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); +unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); +unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); +const unsigned long __sanitizer_bufsiz = BUFSIZ; + +const unsigned IOCTL_NOT_PRESENT = 0; + +unsigned IOCTL_FIOASYNC = FIOASYNC; +unsigned IOCTL_FIOCLEX = FIOCLEX; +unsigned IOCTL_FIOGETOWN = FIOGETOWN; +unsigned IOCTL_FIONBIO = FIONBIO; +unsigned IOCTL_FIONCLEX = FIONCLEX; +unsigned IOCTL_FIOSETOWN = FIOSETOWN; +unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; +unsigned IOCTL_SIOCATMARK = SIOCATMARK; +unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; +unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; +unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; +unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; +unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; +unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; +unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; +unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; +unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; +unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; +unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; +unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; +unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; +unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; +unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; +unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; +unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; +unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; +unsigned IOCTL_TIOCCONS = TIOCCONS; +unsigned IOCTL_TIOCEXCL = TIOCEXCL; +unsigned IOCTL_TIOCGETD = TIOCGETD; +unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; +unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; +unsigned IOCTL_TIOCMBIC = TIOCMBIC; +unsigned IOCTL_TIOCMBIS = TIOCMBIS; +unsigned IOCTL_TIOCMGET = TIOCMGET; +unsigned IOCTL_TIOCMSET = TIOCMSET; +unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; +unsigned IOCTL_TIOCNXCL = TIOCNXCL; +unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; +unsigned IOCTL_TIOCPKT = TIOCPKT; +unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; +unsigned IOCTL_TIOCSETD = TIOCSETD; +unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; +unsigned IOCTL_TIOCSTI = TIOCSTI; +unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; +unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; +unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; +unsigned IOCTL_MTIOCGET = MTIOCGET; +unsigned IOCTL_MTIOCTOP = MTIOCTOP; +unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; +unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; +unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; +unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; +unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; +unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; +unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; +unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; +unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; +unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; +unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; +unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; +unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; +unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; +unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; +unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; +unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; +unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; +unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; +unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; +unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; +unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; +unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; +unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; +unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; +unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; +unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; +unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; +unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; +unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; +unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; +unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; +unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; +unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; +unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; +unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; +unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; +unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; +unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; +unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; +unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; +unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; +unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; +unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; +unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; +unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; +unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; +unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; +unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; +unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; +unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; +unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; +unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; +unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; +unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; +unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; +unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; +unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; +unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; +unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; +unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; +unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; +unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; +unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; +unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; +unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; +unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; +unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; +unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; +unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; +unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; +unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; +unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; +unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; +unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; +unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; +unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; +unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; +unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; +unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; +unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; +unsigned IOCTL_VT_GETMODE = VT_GETMODE; +unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; +unsigned IOCTL_VT_RELDISP = VT_RELDISP; +unsigned IOCTL_VT_SETMODE = VT_SETMODE; +unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; +unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; +unsigned IOCTL_KDDISABIO = KDDISABIO; +unsigned IOCTL_KDENABIO = KDENABIO; +unsigned IOCTL_KDGETLED = KDGETLED; +unsigned IOCTL_KDGETMODE = KDGETMODE; +unsigned IOCTL_KDGKBMODE = KDGKBMODE; +unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; +unsigned IOCTL_KDMKTONE = KDMKTONE; +unsigned IOCTL_KDSETLED = KDSETLED; +unsigned IOCTL_KDSETMODE = KDSETMODE; +unsigned IOCTL_KDSKBMODE = KDSKBMODE; +unsigned IOCTL_KIOCSOUND = KIOCSOUND; +unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; +unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; + +const int si_SEGV_MAPERR = SEGV_MAPERR; +const int si_SEGV_ACCERR = SEGV_ACCERR; +const int unvis_valid = UNVIS_VALID; +const int unvis_validpush = UNVIS_VALIDPUSH; +} // namespace __sanitizer using namespace __sanitizer; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h index 71cf5b9c35715..5e0ca9c7d7823 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h @@ -18,18 +18,17 @@ #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" - #include "sanitizer_platform_limits_posix.h" -// FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that -// incorporates the map structure. -# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ - ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 560))) // Get sys/_types.h, because that tells us whether 64-bit inodes are // used in struct dirent below. #include namespace __sanitizer { +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle); +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle) + extern unsigned struct_utsname_sz; extern unsigned struct_stat_sz; #if defined(__powerpc64__) @@ -53,6 +52,7 @@ extern unsigned struct_timezone_sz; extern unsigned struct_tms_sz; extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; extern unsigned struct_sched_param_sz; extern unsigned struct_statfs64_sz; extern unsigned struct_statfs_sz; @@ -147,7 +147,7 @@ struct __sanitizer_ifaddrs { unsigned int ifa_flags; void *ifa_addr; // (struct sockaddr *) void *ifa_netmask; // (struct sockaddr *) -# undef ifa_dstaddr +#undef ifa_dstaddr void *ifa_dstaddr; // (struct sockaddr *) void *ifa_data; }; @@ -630,27 +630,27 @@ extern unsigned struct_cap_rights_sz; extern unsigned struct_fstab_sz; extern unsigned struct_StringList_sz; -} // namespace __sanitizer +} // namespace __sanitizer #define CHECK_TYPE_SIZE(TYPE) \ COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) -#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ - COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \ - sizeof(((CLASS *) NULL)->MEMBER)); \ - COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ +#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ offsetof(CLASS, MEMBER)) // For sigaction, which is a function and struct at the same time, // and thus requires explicit "struct" in sizeof() expression. -#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ - COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \ - sizeof(((struct CLASS *) NULL)->MEMBER)); \ - COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ +#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((struct CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ offsetof(struct CLASS, MEMBER)) #define SIGACTION_SYMNAME sigaction #endif -#endif // SANITIZER_FREEBSD +#endif // SANITIZER_FREEBSD diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp index 48a78c8998a21..c8f2aa5dba4af 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,7 @@ #include #include +#include #include #include #include @@ -139,7 +141,158 @@ #include #include #include +#if __has_include() #include +#else +/* Fallback for MKISCSI=no */ + +typedef struct { + uint32_t status; + uint32_t session_id; + uint32_t connection_id; +} iscsi_conn_status_parameters_t; + +typedef struct { + uint32_t status; + uint16_t interface_version; + uint16_t major; + uint16_t minor; + uint8_t version_string[224]; +} iscsi_get_version_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; + uint32_t connection_id; + struct { + unsigned int immediate : 1; + } options; + uint64_t lun; + scsireq_t req; /* from */ +} iscsi_iocommand_parameters_t; + +typedef enum { + ISCSI_AUTH_None = 0, + ISCSI_AUTH_CHAP = 1, + ISCSI_AUTH_KRB5 = 2, + ISCSI_AUTH_SRP = 3 +} iscsi_auth_types_t; + +typedef enum { + ISCSI_LOGINTYPE_DISCOVERY = 0, + ISCSI_LOGINTYPE_NOMAP = 1, + ISCSI_LOGINTYPE_MAP = 2 +} iscsi_login_session_type_t; + +typedef enum { ISCSI_DIGEST_None = 0, ISCSI_DIGEST_CRC32C = 1 } iscsi_digest_t; + +typedef enum { + ISCSI_SESSION_TERMINATED = 1, + ISCSI_CONNECTION_TERMINATED, + ISCSI_RECOVER_CONNECTION, + ISCSI_DRIVER_TERMINATING +} iscsi_event_t; + +typedef struct { + unsigned int mutual_auth : 1; + unsigned int is_secure : 1; + unsigned int auth_number : 4; + iscsi_auth_types_t auth_type[4]; +} iscsi_auth_info_t; + +typedef struct { + uint32_t status; + int socket; + struct { + unsigned int HeaderDigest : 1; + unsigned int DataDigest : 1; + unsigned int MaxConnections : 1; + unsigned int DefaultTime2Wait : 1; + unsigned int DefaultTime2Retain : 1; + unsigned int MaxRecvDataSegmentLength : 1; + unsigned int auth_info : 1; + unsigned int user_name : 1; + unsigned int password : 1; + unsigned int target_password : 1; + unsigned int TargetName : 1; + unsigned int TargetAlias : 1; + unsigned int ErrorRecoveryLevel : 1; + } is_present; + iscsi_auth_info_t auth_info; + iscsi_login_session_type_t login_type; + iscsi_digest_t HeaderDigest; + iscsi_digest_t DataDigest; + uint32_t session_id; + uint32_t connection_id; + uint32_t MaxRecvDataSegmentLength; + uint16_t MaxConnections; + uint16_t DefaultTime2Wait; + uint16_t DefaultTime2Retain; + uint16_t ErrorRecoveryLevel; + void *user_name; + void *password; + void *target_password; + void *TargetName; + void *TargetAlias; +} iscsi_login_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; +} iscsi_logout_parameters_t; + +typedef struct { + uint32_t status; + uint32_t event_id; +} iscsi_register_event_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; + uint32_t connection_id; +} iscsi_remove_parameters_t; + +typedef struct { + uint32_t status; + uint32_t session_id; + void *response_buffer; + uint32_t response_size; + uint32_t response_used; + uint32_t response_total; + uint8_t key[224]; +} iscsi_send_targets_parameters_t; + +typedef struct { + uint32_t status; + uint8_t InitiatorName[224]; + uint8_t InitiatorAlias[224]; + uint8_t ISID[6]; +} iscsi_set_node_name_parameters_t; + +typedef struct { + uint32_t status; + uint32_t event_id; + iscsi_event_t event_kind; + uint32_t session_id; + uint32_t connection_id; + uint32_t reason; +} iscsi_wait_event_parameters_t; + +#define ISCSI_GET_VERSION _IOWR(0, 1, iscsi_get_version_parameters_t) +#define ISCSI_LOGIN _IOWR(0, 2, iscsi_login_parameters_t) +#define ISCSI_LOGOUT _IOWR(0, 3, iscsi_logout_parameters_t) +#define ISCSI_ADD_CONNECTION _IOWR(0, 4, iscsi_login_parameters_t) +#define ISCSI_RESTORE_CONNECTION _IOWR(0, 5, iscsi_login_parameters_t) +#define ISCSI_REMOVE_CONNECTION _IOWR(0, 6, iscsi_remove_parameters_t) +#define ISCSI_CONNECTION_STATUS _IOWR(0, 7, iscsi_conn_status_parameters_t) +#define ISCSI_SEND_TARGETS _IOWR(0, 8, iscsi_send_targets_parameters_t) +#define ISCSI_SET_NODE_NAME _IOWR(0, 9, iscsi_set_node_name_parameters_t) +#define ISCSI_IO_COMMAND _IOWR(0, 10, iscsi_iocommand_parameters_t) +#define ISCSI_REGISTER_EVENT _IOWR(0, 11, iscsi_register_event_parameters_t) +#define ISCSI_DEREGISTER_EVENT _IOWR(0, 12, iscsi_register_event_parameters_t) +#define ISCSI_WAIT_EVENT _IOWR(0, 13, iscsi_wait_event_parameters_t) +#define ISCSI_POLL_EVENT _IOWR(0, 14, iscsi_wait_event_parameters_t) +#endif #include #include #include @@ -161,12 +314,121 @@ #include #include #include +#if __has_include() #include #include #include +#else +/* Fallback for MKIPFILTER=no */ + +typedef struct ap_control { + char apc_label[16]; + char apc_config[16]; + unsigned char apc_p; + unsigned long apc_cmd; + unsigned long apc_arg; + void *apc_data; + size_t apc_dsize; +} ap_ctl_t; + +typedef struct ipftq { + ipfmutex_t ifq_lock; + unsigned int ifq_ttl; + void *ifq_head; + void **ifq_tail; + void *ifq_next; + void **ifq_pnext; + int ifq_ref; + unsigned int ifq_flags; +} ipftq_t; + +typedef struct ipfobj { + uint32_t ipfo_rev; + uint32_t ipfo_size; + void *ipfo_ptr; + int ipfo_type; + int ipfo_offset; + int ipfo_retval; + unsigned char ipfo_xxxpad[28]; +} ipfobj_t; + +#define SIOCADNAT _IOW('r', 60, struct ipfobj) +#define SIOCRMNAT _IOW('r', 61, struct ipfobj) +#define SIOCGNATS _IOWR('r', 62, struct ipfobj) +#define SIOCGNATL _IOWR('r', 63, struct ipfobj) +#define SIOCPURGENAT _IOWR('r', 100, struct ipfobj) +#endif #include #include +#if !__NetBSD_Prereq__(9, 99, 51) #include +#else +struct smbioc_flags { + int ioc_level; + int ioc_mask; + int ioc_flags; +}; +struct smbioc_oshare { + int ioc_opt; + int ioc_stype; + char ioc_share[129]; + char ioc_password[129]; + uid_t ioc_owner; + gid_t ioc_group; + mode_t ioc_mode; + mode_t ioc_rights; +}; +struct smbioc_ossn { + int ioc_opt; + uint32_t ioc_svlen; + struct sockaddr *ioc_server; + uint32_t ioc_lolen; + struct sockaddr *ioc_local; + char ioc_srvname[16]; + int ioc_timeout; + int ioc_retrycount; + char ioc_localcs[16]; + char ioc_servercs[16]; + char ioc_user[129]; + char ioc_workgroup[129]; + char ioc_password[129]; + uid_t ioc_owner; + gid_t ioc_group; + mode_t ioc_mode; + mode_t ioc_rights; +}; +struct smbioc_lookup { + int ioc_level; + int ioc_flags; + struct smbioc_ossn ioc_ssn; + struct smbioc_oshare ioc_sh; +}; +struct smbioc_rq { + u_char ioc_cmd; + u_char ioc_twc; + void *ioc_twords; + u_short ioc_tbc; + void *ioc_tbytes; + int ioc_rpbufsz; + char *ioc_rpbuf; + u_char ioc_rwc; + u_short ioc_rbc; +}; +struct smbioc_rw { + u_int16_t ioc_fh; + char *ioc_base; + off_t ioc_offset; + int ioc_cnt; +}; +#define SMBIOC_OPENSESSION _IOW('n', 100, struct smbioc_ossn) +#define SMBIOC_OPENSHARE _IOW('n', 101, struct smbioc_oshare) +#define SMBIOC_REQUEST _IOWR('n', 102, struct smbioc_rq) +#define SMBIOC_T2RQ _IOWR('n', 103, struct smbioc_t2rq) +#define SMBIOC_SETFLAGS _IOW('n', 104, struct smbioc_flags) +#define SMBIOC_LOOKUP _IOW('n', 106, struct smbioc_lookup) +#define SMBIOC_READ _IOWR('n', 107, struct smbioc_rw) +#define SMBIOC_WRITE _IOWR('n', 108, struct smbioc_rw) +#endif #include #include #include @@ -190,7 +452,21 @@ #include #include #include +#if !__NetBSD_Prereq__(9, 99, 44) #include +#else +struct urio_command { + unsigned short length; + int request; + int requesttype; + int value; + int index; + void *buffer; + int timeout; +}; +#define URIO_SEND_COMMAND _IOWR('U', 200, struct urio_command) +#define URIO_RECV_COMMAND _IOWR('U', 201, struct urio_command) +#endif #include #include #include @@ -199,6 +475,7 @@ #include #include #include +#include #include #include #include @@ -244,9 +521,15 @@ // Include these after system headers to avoid name clashes and ambiguities. #include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" #include "sanitizer_platform_limits_netbsd.h" namespace __sanitizer { +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) { + void *p = nullptr; + return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr; +} + unsigned struct_utsname_sz = sizeof(struct utsname); unsigned struct_stat_sz = sizeof(struct stat); unsigned struct_rusage_sz = sizeof(struct rusage); @@ -255,6 +538,7 @@ unsigned struct_passwd_sz = sizeof(struct passwd); unsigned struct_group_sz = sizeof(struct group); unsigned siginfo_t_sz = sizeof(siginfo_t); unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_stack_t_sz = sizeof(stack_t); unsigned struct_itimerval_sz = sizeof(struct itimerval); unsigned pthread_t_sz = sizeof(pthread_t); unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h index 794efdb6eff6d..9e28dcfef0415 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -19,18 +19,11 @@ #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" -#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \ - ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift)))) - -#if defined(__x86_64__) -#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ - _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 264) -#elif defined(__i386__) +namespace __sanitizer { +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle); #define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ - _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 136) -#endif + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle) -namespace __sanitizer { extern unsigned struct_utsname_sz; extern unsigned struct_stat_sz; extern unsigned struct_rusage_sz; @@ -48,6 +41,7 @@ extern unsigned struct_timezone_sz; extern unsigned struct_tms_sz; extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; extern unsigned struct_sched_param_sz; extern unsigned struct_statfs_sz; extern unsigned struct_sockaddr_sz; @@ -1030,12 +1024,10 @@ extern unsigned struct_RF_ProgressInfo_sz; extern unsigned struct_nvlist_ref_sz; extern unsigned struct_StringList_sz; - // A special value to mark ioctls that are not present on the target platform, // when it can not be determined without including any system headers. extern const unsigned IOCTL_NOT_PRESENT; - extern unsigned IOCTL_AFM_ADDFMAP; extern unsigned IOCTL_AFM_DELFMAP; extern unsigned IOCTL_AFM_CLEANFMAP; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp index 12515626ce534..e69de29bb2d1d 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp @@ -1,278 +0,0 @@ -//===-- sanitizer_platform_limits_openbsd.cpp -----------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of Sanitizer common code. -// -// Sizes and layouts of platform-specific NetBSD data structures. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" - -#if SANITIZER_OPENBSD -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Include these after system headers to avoid name clashes and ambiguities. -#include "sanitizer_internal_defs.h" -#include "sanitizer_platform_limits_openbsd.h" - -namespace __sanitizer { -unsigned struct_utsname_sz = sizeof(struct utsname); -unsigned struct_stat_sz = sizeof(struct stat); -unsigned struct_rusage_sz = sizeof(struct rusage); -unsigned struct_tm_sz = sizeof(struct tm); -unsigned struct_passwd_sz = sizeof(struct passwd); -unsigned struct_group_sz = sizeof(struct group); -unsigned siginfo_t_sz = sizeof(siginfo_t); -unsigned struct_sigaction_sz = sizeof(struct sigaction); -unsigned struct_itimerval_sz = sizeof(struct itimerval); -unsigned pthread_t_sz = sizeof(pthread_t); -unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); -unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); -unsigned pid_t_sz = sizeof(pid_t); -unsigned timeval_sz = sizeof(timeval); -unsigned uid_t_sz = sizeof(uid_t); -unsigned gid_t_sz = sizeof(gid_t); -unsigned mbstate_t_sz = sizeof(mbstate_t); -unsigned sigset_t_sz = sizeof(sigset_t); -unsigned struct_timezone_sz = sizeof(struct timezone); -unsigned struct_tms_sz = sizeof(struct tms); -unsigned struct_sched_param_sz = sizeof(struct sched_param); -unsigned struct_sockaddr_sz = sizeof(struct sockaddr); -unsigned struct_rlimit_sz = sizeof(struct rlimit); -unsigned struct_timespec_sz = sizeof(struct timespec); -unsigned struct_utimbuf_sz = sizeof(struct utimbuf); -unsigned struct_itimerspec_sz = sizeof(struct itimerspec); -unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); -unsigned struct_statvfs_sz = sizeof(struct statvfs); - -const uptr sig_ign = (uptr)SIG_IGN; -const uptr sig_dfl = (uptr)SIG_DFL; -const uptr sig_err = (uptr)SIG_ERR; -const uptr sa_siginfo = (uptr)SA_SIGINFO; - -int shmctl_ipc_stat = (int)IPC_STAT; - -unsigned struct_utmp_sz = sizeof(struct utmp); - -int map_fixed = MAP_FIXED; - -int af_inet = (int)AF_INET; -int af_inet6 = (int)AF_INET6; - -uptr __sanitizer_in_addr_sz(int af) { - if (af == AF_INET) - return sizeof(struct in_addr); - else if (af == AF_INET6) - return sizeof(struct in6_addr); - else - return 0; -} - -unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); - -int glob_nomatch = GLOB_NOMATCH; -int glob_altdirfunc = GLOB_ALTDIRFUNC; - -unsigned path_max = PATH_MAX; - -const int si_SEGV_MAPERR = SEGV_MAPERR; -const int si_SEGV_ACCERR = SEGV_ACCERR; -} // namespace __sanitizer - -using namespace __sanitizer; - -COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); - -COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); -CHECK_TYPE_SIZE(pthread_key_t); - -CHECK_TYPE_SIZE(dl_phdr_info); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); -CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); - -CHECK_TYPE_SIZE(glob_t); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); -CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); -CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); -CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); -CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); -CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); -CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); - -CHECK_TYPE_SIZE(addrinfo); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); -CHECK_SIZE_AND_OFFSET(addrinfo, ai_next); - -CHECK_TYPE_SIZE(hostent); -CHECK_SIZE_AND_OFFSET(hostent, h_name); -CHECK_SIZE_AND_OFFSET(hostent, h_aliases); -CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); -CHECK_SIZE_AND_OFFSET(hostent, h_length); -CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); - -CHECK_TYPE_SIZE(iovec); -CHECK_SIZE_AND_OFFSET(iovec, iov_base); -CHECK_SIZE_AND_OFFSET(iovec, iov_len); - -CHECK_TYPE_SIZE(msghdr); -CHECK_SIZE_AND_OFFSET(msghdr, msg_name); -CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); -CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_control); -CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); -CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); - -CHECK_TYPE_SIZE(cmsghdr); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); -CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); - -COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); -CHECK_SIZE_AND_OFFSET(dirent, d_fileno); -CHECK_SIZE_AND_OFFSET(dirent, d_off); -CHECK_SIZE_AND_OFFSET(dirent, d_reclen); - -CHECK_TYPE_SIZE(ifconf); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); -CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); - -CHECK_TYPE_SIZE(pollfd); -CHECK_SIZE_AND_OFFSET(pollfd, fd); -CHECK_SIZE_AND_OFFSET(pollfd, events); -CHECK_SIZE_AND_OFFSET(pollfd, revents); - -CHECK_TYPE_SIZE(nfds_t); - -CHECK_TYPE_SIZE(sigset_t); - -COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); -// Can't write checks for sa_handler and sa_sigaction due to them being -// preprocessor macros. -CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); - -CHECK_TYPE_SIZE(tm); -CHECK_SIZE_AND_OFFSET(tm, tm_sec); -CHECK_SIZE_AND_OFFSET(tm, tm_min); -CHECK_SIZE_AND_OFFSET(tm, tm_hour); -CHECK_SIZE_AND_OFFSET(tm, tm_mday); -CHECK_SIZE_AND_OFFSET(tm, tm_mon); -CHECK_SIZE_AND_OFFSET(tm, tm_year); -CHECK_SIZE_AND_OFFSET(tm, tm_wday); -CHECK_SIZE_AND_OFFSET(tm, tm_yday); -CHECK_SIZE_AND_OFFSET(tm, tm_isdst); -CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); -CHECK_SIZE_AND_OFFSET(tm, tm_zone); - -CHECK_TYPE_SIZE(ipc_perm); -CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); -CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); -CHECK_SIZE_AND_OFFSET(ipc_perm, uid); -CHECK_SIZE_AND_OFFSET(ipc_perm, gid); -CHECK_SIZE_AND_OFFSET(ipc_perm, mode); -CHECK_SIZE_AND_OFFSET(ipc_perm, seq); -CHECK_SIZE_AND_OFFSET(ipc_perm, key); - -CHECK_TYPE_SIZE(shmid_ds); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); -CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_atimensec); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); -CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_dtimensec); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); -CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_ctimensec); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); -CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); - -CHECK_TYPE_SIZE(clock_t); - -CHECK_TYPE_SIZE(ifaddrs); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); -// Compare against the union, because we can't reach into the union in a -// compliant way. -#ifdef ifa_dstaddr -#undef ifa_dstaddr -#endif -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); -CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); - -CHECK_TYPE_SIZE(passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_name); -CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); -CHECK_SIZE_AND_OFFSET(passwd, pw_uid); -CHECK_SIZE_AND_OFFSET(passwd, pw_gid); -CHECK_SIZE_AND_OFFSET(passwd, pw_dir); -CHECK_SIZE_AND_OFFSET(passwd, pw_shell); - -CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); - -CHECK_TYPE_SIZE(group); -CHECK_SIZE_AND_OFFSET(group, gr_name); -CHECK_SIZE_AND_OFFSET(group, gr_passwd); -CHECK_SIZE_AND_OFFSET(group, gr_gid); -CHECK_SIZE_AND_OFFSET(group, gr_mem); - -#endif // SANITIZER_OPENBSD diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h index 6d8b062716b78..e69de29bb2d1d 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h @@ -1,381 +0,0 @@ -//===-- sanitizer_platform_limits_openbsd.h -------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of Sanitizer common code. -// -// Sizes and layouts of platform-specific OpenBSD data structures. -//===----------------------------------------------------------------------===// - -#ifndef SANITIZER_PLATFORM_LIMITS_OPENBSD_H -#define SANITIZER_PLATFORM_LIMITS_OPENBSD_H - -#if SANITIZER_OPENBSD - -#include "sanitizer_internal_defs.h" -#include "sanitizer_platform.h" - -#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \ - ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift)))) - -#if defined(__x86_64__) -#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ - _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 312) -#elif defined(__i386__) -#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ - _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 164) -#endif - -#define RLIMIT_AS RLIMIT_DATA - -namespace __sanitizer { -extern unsigned struct_utsname_sz; -extern unsigned struct_stat_sz; -extern unsigned struct_rusage_sz; -extern unsigned siginfo_t_sz; -extern unsigned struct_itimerval_sz; -extern unsigned pthread_t_sz; -extern unsigned pthread_mutex_t_sz; -extern unsigned pthread_cond_t_sz; -extern unsigned pid_t_sz; -extern unsigned timeval_sz; -extern unsigned uid_t_sz; -extern unsigned gid_t_sz; -extern unsigned mbstate_t_sz; -extern unsigned struct_timezone_sz; -extern unsigned struct_tms_sz; -extern unsigned struct_itimerspec_sz; -extern unsigned struct_sigevent_sz; -extern unsigned struct_statfs_sz; -extern unsigned struct_sockaddr_sz; - -extern unsigned struct_rlimit_sz; -extern unsigned struct_utimbuf_sz; -extern unsigned struct_timespec_sz; - -struct __sanitizer_iocb { - u64 aio_offset; - uptr aio_buf; - long aio_nbytes; - u32 aio_fildes; - u32 aio_lio_opcode; - long aio_reqprio; -#if SANITIZER_WORDSIZE == 64 - u8 aio_sigevent[32]; -#else - u8 aio_sigevent[20]; -#endif - u32 _state; - u32 _errno; - long _retval; -}; - -struct __sanitizer___sysctl_args { - int *name; - int nlen; - void *oldval; - uptr *oldlenp; - void *newval; - uptr newlen; -}; - -struct __sanitizer_sem_t { - uptr data[5]; -}; - -struct __sanitizer_ipc_perm { - u32 cuid; - u32 cgid; - u32 uid; - u32 gid; - u32 mode; - unsigned short seq; - long key; -}; - -struct __sanitizer_shmid_ds { - __sanitizer_ipc_perm shm_perm; - int shm_segsz; - u32 shm_lpid; - u32 shm_cpid; - short shm_nattch; - u64 shm_atime; - long __shm_atimensec; - u64 shm_dtime; - long __shm_dtimensec; - u64 shm_ctime; - long __shm_ctimensec; - void *_shm_internal; -}; - -extern unsigned struct_msqid_ds_sz; -extern unsigned struct_mq_attr_sz; -extern unsigned struct_timex_sz; -extern unsigned struct_statvfs_sz; - -struct __sanitizer_iovec { - void *iov_base; - uptr iov_len; -}; - -struct __sanitizer_ifaddrs { - struct __sanitizer_ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - struct __sanitizer_sockaddr *ifa_addr; // (struct sockaddr *) - struct __sanitizer_sockaddr *ifa_netmask; // (struct sockaddr *) - struct __sanitizer_sockaddr *ifa_dstaddr; // (struct sockaddr *) - void *ifa_data; -}; - -typedef unsigned __sanitizer_pthread_key_t; - -typedef long long __sanitizer_time_t; -typedef int __sanitizer_suseconds_t; - -struct __sanitizer_timeval { - __sanitizer_time_t tv_sec; - __sanitizer_suseconds_t tv_usec; -}; - -struct __sanitizer_itimerval { - struct __sanitizer_timeval it_interval; - struct __sanitizer_timeval it_value; -}; - -struct __sanitizer_passwd { - char *pw_name; - char *pw_passwd; - int pw_uid; - int pw_gid; - __sanitizer_time_t pw_change; - char *pw_class; - char *pw_gecos; - char *pw_dir; - char *pw_shell; - __sanitizer_time_t pw_expire; -}; - -struct __sanitizer_group { - char *gr_name; - char *gr_passwd; - int gr_gid; - char **gr_mem; -}; - -struct __sanitizer_ether_addr { - u8 octet[6]; -}; - -struct __sanitizer_tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - long int tm_gmtoff; - const char *tm_zone; -}; - -struct __sanitizer_msghdr { - void *msg_name; - unsigned msg_namelen; - struct __sanitizer_iovec *msg_iov; - unsigned msg_iovlen; - void *msg_control; - unsigned msg_controllen; - int msg_flags; -}; -struct __sanitizer_cmsghdr { - unsigned cmsg_len; - int cmsg_level; - int cmsg_type; -}; - -struct __sanitizer_dirent { - u64 d_fileno; - u64 d_off; - u16 d_reclen; -}; - -typedef u64 __sanitizer_clock_t; -typedef u32 __sanitizer_clockid_t; - -typedef u32 __sanitizer___kernel_uid_t; -typedef u32 __sanitizer___kernel_gid_t; -typedef u64 __sanitizer___kernel_off_t; -typedef struct { - u32 fds_bits[8]; -} __sanitizer___kernel_fd_set; - -typedef struct { - unsigned int pta_magic; - int pta_flags; - void *pta_private; -} __sanitizer_pthread_attr_t; - -typedef unsigned int __sanitizer_sigset_t; - -struct __sanitizer_siginfo { - // The size is determined by looking at sizeof of real siginfo_t on linux. - u64 opaque[128 / sizeof(u64)]; -}; - -using __sanitizer_sighandler_ptr = void (*)(int sig); -using __sanitizer_sigactionhandler_ptr = void (*)(int sig, - __sanitizer_siginfo *siginfo, - void *uctx); - -struct __sanitizer_sigaction { - union { - __sanitizer_sighandler_ptr handler; - __sanitizer_sigactionhandler_ptr sigaction; - }; - __sanitizer_sigset_t sa_mask; - int sa_flags; -}; - -typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; - -struct __sanitizer_kernel_sigaction_t { - union { - void (*handler)(int signo); - void (*sigaction)(int signo, void *info, void *ctx); - }; - unsigned long sa_flags; - void (*sa_restorer)(void); - __sanitizer_kernel_sigset_t sa_mask; -}; - -extern const uptr sig_ign; -extern const uptr sig_dfl; -extern const uptr sig_err; -extern const uptr sa_siginfo; - -extern int af_inet; -extern int af_inet6; -uptr __sanitizer_in_addr_sz(int af); - -struct __sanitizer_dl_phdr_info { -#if SANITIZER_WORDSIZE == 64 - u64 dlpi_addr; -#else - u32 dlpi_addr; -#endif - const char *dlpi_name; - const void *dlpi_phdr; -#if SANITIZER_WORDSIZE == 64 - u32 dlpi_phnum; -#else - u16 dlpi_phnum; -#endif -}; - -extern unsigned struct_ElfW_Phdr_sz; - -struct __sanitizer_addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - unsigned ai_addrlen; - struct __sanitizer_sockaddr *ai_addr; - char *ai_canonname; - struct __sanitizer_addrinfo *ai_next; -}; - -struct __sanitizer_hostent { - char *h_name; - char **h_aliases; - int h_addrtype; - int h_length; - char **h_addr_list; -}; - -struct __sanitizer_pollfd { - int fd; - short events; - short revents; -}; - -typedef unsigned __sanitizer_nfds_t; - -struct __sanitizer_glob_t { - int gl_pathc; - int gl_matchc; - int gl_offs; - int gl_flags; - char **gl_pathv; - void **gl_statv; - int (*gl_errfunc)(const char *, int); - void (*gl_closedir)(void *dirp); - struct dirent *(*gl_readdir)(void *dirp); - void *(*gl_opendir)(const char *); - int (*gl_lstat)(const char *, void * /* struct stat* */); - int (*gl_stat)(const char *, void * /* struct stat* */); -}; - -extern int glob_nomatch; -extern int glob_altdirfunc; - -extern unsigned path_max; - -typedef char __sanitizer_FILE; -#define SANITIZER_HAS_STRUCT_FILE 0 - -extern int shmctl_ipc_stat; - -// This simplifies generic code -#define struct_shminfo_sz -1 -#define struct_shm_info_sz -1 -#define shmctl_shm_stat -1 -#define shmctl_ipc_info -1 -#define shmctl_shm_info -1 - -extern unsigned struct_utmp_sz; -extern unsigned struct_utmpx_sz; - -extern int map_fixed; - -// ioctl arguments -struct __sanitizer_ifconf { - int ifc_len; - union { - void *ifcu_req; - } ifc_ifcu; -}; - -extern const int si_SEGV_MAPERR; -extern const int si_SEGV_ACCERR; -} // namespace __sanitizer - -#define CHECK_TYPE_SIZE(TYPE) \ - COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) - -#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ - COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ - sizeof(((CLASS *)NULL)->MEMBER)); \ - COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ - offsetof(CLASS, MEMBER)) - -// For sigaction, which is a function and struct at the same time, -// and thus requires explicit "struct" in sizeof() expression. -#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ - COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ - sizeof(((struct CLASS *)NULL)->MEMBER)); \ - COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ - offsetof(struct CLASS, MEMBER)) - -#define SIGACTION_SYMNAME __sigaction14 - -#endif // SANITIZER_OPENBSD - -#endif diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp index c44449aee09a6..fe8b04a9c4880 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -11,18 +11,19 @@ // Sizes and layouts of platform-specific POSIX data structures. //===----------------------------------------------------------------------===// -#include "sanitizer_platform.h" - -#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN +#if defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__) // Tests in this file assume that off_t-dependent data structures match the // libc ABI. For example, struct dirent here is what readdir() function (as // exported from libc) returns, and not the user-facing "dirent", which // depends on _FILE_OFFSET_BITS setting. // To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below. -#ifdef _FILE_OFFSET_BITS #undef _FILE_OFFSET_BITS #endif +// Must go after undef _FILE_OFFSET_BITS. +#include "sanitizer_platform.h" + +#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN // Must go after undef _FILE_OFFSET_BITS. #include "sanitizer_glibc_version.h" @@ -37,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -58,7 +60,6 @@ #endif #if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN -#include #include #include #include @@ -90,7 +91,8 @@ #if SANITIZER_LINUX # include # include -# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) +#if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \ + SANITIZER_RISCV64 # include # ifdef __arm__ typedef struct user_fpregs elf_fpregset_t; @@ -109,20 +111,31 @@ typedef struct user_fpregs elf_fpregset_t; #include #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID -#include -#include -#include +#if SANITIZER_LINUX +#if SANITIZER_GLIBC +#include #include #include #include #include +#include #if HAVE_RPC_XDR_H # include #endif #include -#include +#else +#include +#include +#include +#endif // SANITIZER_GLIBC + +#if SANITIZER_ANDROID +#include +#else +#include +#include #include +#include #include #include #include @@ -141,20 +154,14 @@ typedef struct user_fpregs elf_fpregset_t; #include #include #include -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID +#endif // SANITIZER_ANDROID -#if SANITIZER_ANDROID -#include -#include -#include -#include -#endif - -#if SANITIZER_LINUX #include #include #include #include +#elif !SANITIZER_EMSCRIPTEN +#include #endif // SANITIZER_LINUX #if SANITIZER_MAC @@ -170,15 +177,16 @@ typedef struct user_fpregs elf_fpregset_t; namespace __sanitizer { unsigned struct_utsname_sz = sizeof(struct utsname); unsigned struct_stat_sz = sizeof(struct stat); -#if !SANITIZER_IOS +#if !SANITIZER_IOS && !(SANITIZER_MAC && TARGET_CPU_ARM64) unsigned struct_stat64_sz = sizeof(struct stat64); -#endif // !SANITIZER_IOS +#endif // !SANITIZER_IOS && !(SANITIZER_MAC && TARGET_CPU_ARM64) unsigned struct_rusage_sz = sizeof(struct rusage); unsigned struct_tm_sz = sizeof(struct tm); unsigned struct_passwd_sz = sizeof(struct passwd); unsigned struct_group_sz = sizeof(struct group); unsigned siginfo_t_sz = sizeof(siginfo_t); unsigned struct_sigaction_sz = sizeof(struct sigaction); + unsigned struct_stack_t_sz = sizeof(stack_t); unsigned struct_itimerval_sz = sizeof(struct itimerval); unsigned pthread_t_sz = sizeof(pthread_t); unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); @@ -196,12 +204,14 @@ namespace __sanitizer { unsigned struct_regex_sz = sizeof(regex_t); unsigned struct_regmatch_sz = sizeof(regmatch_t); -#if SANITIZER_MAC && !SANITIZER_IOS +#if (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS unsigned struct_statfs64_sz = sizeof(struct statfs64); -#endif // SANITIZER_MAC && !SANITIZER_IOS +#endif // (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS -#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC unsigned struct_fstab_sz = sizeof(struct fstab); +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN unsigned struct_statfs_sz = sizeof(struct statfs); unsigned struct_sockaddr_sz = sizeof(struct sockaddr); unsigned ucontext_t_sz = sizeof(ucontext_t); @@ -228,9 +238,9 @@ namespace __sanitizer { #if SANITIZER_LINUX && !SANITIZER_ANDROID // Use pre-computed size of struct ustat to avoid which // has been removed from glibc 2.28. -#if defined(__aarch64__) || defined(__s390x__) || defined (__mips64) \ - || defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) \ - || defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) +#if defined(__aarch64__) || defined(__s390x__) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) || \ + defined(__x86_64__) || SANITIZER_RISCV64 #define SIZEOF_STRUCT_USTAT 32 #elif defined(__arm__) || defined(__i386__) || defined(__mips__) \ || defined(__powerpc__) || defined(__s390__) || defined(__sparc__) @@ -297,18 +307,21 @@ unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr)); unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID +#if SANITIZER_GLIBC int glob_nomatch = GLOB_NOMATCH; int glob_altdirfunc = GLOB_ALTDIRFUNC; #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__)) +#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__) || SANITIZER_RISCV64) #if defined(__mips64) || defined(__powerpc64__) || defined(__arm__) unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); +#elif SANITIZER_RISCV64 + unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); + unsigned struct_user_fpregs_struct_sz = sizeof(struct __riscv_q_ext_state); #elif defined(__aarch64__) unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs); unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state); @@ -320,7 +333,8 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct); #endif // __mips64 || __powerpc64__ || __aarch64__ #if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ - defined(__aarch64__) || defined(__arm__) || defined(__s390__) + defined(__aarch64__) || defined(__arm__) || defined(__s390__) || \ + SANITIZER_RISCV64 unsigned struct_user_fpxregs_struct_sz = 0; #else unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); @@ -419,7 +433,9 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned struct_input_id_sz = sizeof(struct input_id); unsigned struct_mtpos_sz = sizeof(struct mtpos); unsigned struct_rtentry_sz = sizeof(struct rtentry); +#if SANITIZER_GLIBC || SANITIZER_ANDROID unsigned struct_termio_sz = sizeof(struct termio); +#endif unsigned struct_vt_consize_sz = sizeof(struct vt_consize); unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes); unsigned struct_vt_stat_sz = sizeof(struct vt_stat); @@ -444,7 +460,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned struct_vt_mode_sz = sizeof(struct vt_mode); #endif // SANITIZER_LINUX -#if SANITIZER_LINUX && !SANITIZER_ANDROID +#if SANITIZER_GLIBC unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct); unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor); #if EV_VERSION > (0x010000) @@ -467,12 +483,10 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25); unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc); unsigned struct_unimapinit_sz = sizeof(struct unimapinit); -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID -#if SANITIZER_LINUX && !SANITIZER_ANDROID unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); -#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID +#endif // SANITIZER_GLIBC #if !SANITIZER_ANDROID && !SANITIZER_MAC && !SANITIZER_EMSCRIPTEN unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); @@ -882,6 +896,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP; unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR; unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP; +#if SANITIZER_GLIBC unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN; unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST; unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE; @@ -900,6 +915,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS; unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL; unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS; +#endif unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL; unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI; unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI; @@ -970,7 +986,7 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); #endif // SANITIZER_LINUX || SANITIZER_FREEBSD -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID +#if SANITIZER_GLIBC || SANITIZER_FREEBSD CHECK_TYPE_SIZE(glob_t); CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); @@ -981,7 +997,7 @@ CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); -#endif +#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD CHECK_TYPE_SIZE(addrinfo); CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); @@ -1004,17 +1020,27 @@ CHECK_TYPE_SIZE(iovec); CHECK_SIZE_AND_OFFSET(iovec, iov_base); CHECK_SIZE_AND_OFFSET(iovec, iov_len); +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but +// many implementations don't conform to the standard. Since we pick the +// non-conforming glibc definition, exclude the checks for musl (incompatible +// sizes but compatible offsets). CHECK_TYPE_SIZE(msghdr); CHECK_SIZE_AND_OFFSET(msghdr, msg_name); CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); +#if SANITIZER_GLIBC || SANITIZER_ANDROID CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); +#endif CHECK_SIZE_AND_OFFSET(msghdr, msg_control); +#if SANITIZER_GLIBC || SANITIZER_ANDROID CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); +#endif CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); CHECK_TYPE_SIZE(cmsghdr); +#if SANITIZER_GLIBC || SANITIZER_ANDROID CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); +#endif CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); @@ -1128,7 +1154,7 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_passno); CHECK_TYPE_SIZE(ether_addr); #endif -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID +#if SANITIZER_GLIBC || SANITIZER_FREEBSD CHECK_TYPE_SIZE(ipc_perm); # if SANITIZER_FREEBSD CHECK_SIZE_AND_OFFSET(ipc_perm, key); @@ -1190,7 +1216,7 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); #endif -#if SANITIZER_LINUX +#if SANITIZER_GLIBC || SANITIZER_ANDROID COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo)); #endif @@ -1240,7 +1266,7 @@ COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID +#if SANITIZER_GLIBC COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); CHECK_SIZE_AND_OFFSET(FILE, _flags); CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr); @@ -1257,9 +1283,7 @@ CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end); CHECK_SIZE_AND_OFFSET(FILE, _markers); CHECK_SIZE_AND_OFFSET(FILE, _chain); CHECK_SIZE_AND_OFFSET(FILE, _fileno); -#endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk)); CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit); CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev); @@ -1274,7 +1298,7 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read); CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write); CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek); CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close); -#endif +#endif // SANITIZER_GLIBC #if SANITIZER_LINUX || SANITIZER_FREEBSD CHECK_TYPE_SIZE(sem_t); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index b0896f86720b3..769fe36a90f78 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -47,6 +47,7 @@ extern unsigned struct_timezone_sz; extern unsigned struct_tms_sz; extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; extern unsigned struct_sched_param_sz; extern unsigned struct_statfs64_sz; extern unsigned struct_regex_sz; @@ -98,9 +99,9 @@ const unsigned struct_kernel_stat64_sz = 144; const unsigned struct___old_kernel_stat_sz = 0; const unsigned struct_kernel_stat_sz = 64; const unsigned struct_kernel_stat64_sz = 104; -#elif defined(__riscv) && __riscv_xlen == 64 +#elif SANITIZER_RISCV64 const unsigned struct_kernel_stat_sz = 128; -const unsigned struct_kernel_stat64_sz = 104; +const unsigned struct_kernel_stat64_sz = 0; // RISCV64 does not use stat64 #endif struct __sanitizer_perf_event_attr { unsigned type; @@ -442,6 +443,8 @@ struct __sanitizer_cmsghdr { int cmsg_type; }; #else +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but +// many implementations don't conform to the standard. struct __sanitizer_msghdr { void *msg_name; unsigned msg_namelen; @@ -705,6 +708,12 @@ struct __sanitizer_dl_phdr_info { extern unsigned struct_ElfW_Phdr_sz; #endif +struct __sanitizer_protoent { + char *p_name; + char **p_aliases; + int p_proto; +}; + struct __sanitizer_addrinfo { int ai_flags; int ai_family; @@ -799,7 +808,7 @@ typedef void __sanitizer_FILE; #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__)) + defined(__s390__) || SANITIZER_RISCV64) extern unsigned struct_user_regs_struct_sz; extern unsigned struct_user_fpregs_struct_sz; extern unsigned struct_user_fpxregs_struct_sz; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp index 9717d98ebf1aa..565b31f68aaee 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp @@ -72,6 +72,7 @@ namespace __sanitizer { unsigned struct_group_sz = sizeof(struct group); unsigned siginfo_t_sz = sizeof(siginfo_t); unsigned struct_sigaction_sz = sizeof(struct sigaction); + unsigned struct_stack_t_sz = sizeof(stack_t); unsigned struct_itimerval_sz = sizeof(struct itimerval); unsigned pthread_t_sz = sizeof(pthread_t); unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); @@ -201,7 +202,8 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); -CHECK_TYPE_SIZE(glob_t); +// There are additional fields we are not interested in. +COMPILER_CHECK(sizeof(__sanitizer_glob_t) <= sizeof(glob_t)); CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h index 77ae6e6a44dbd..85995e79792d2 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h @@ -38,6 +38,7 @@ extern unsigned struct_timezone_sz; extern unsigned struct_tms_sz; extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; extern unsigned struct_sched_param_sz; extern unsigned struct_statfs64_sz; extern unsigned struct_statfs_sz; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp index fea3483506f26..fd9025882db1e 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp @@ -249,6 +249,7 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { return true; } +#if !SANITIZER_MAC void DumpProcessMap() { MemoryMappingLayout proc_maps(/*cache_enabled*/true); const sptr kBufSize = 4095; @@ -263,6 +264,7 @@ void DumpProcessMap() { UnmapOrDie(filename, kBufSize); } #endif +#endif const char *GetPwd() { return GetEnv("PWD"); @@ -309,7 +311,7 @@ uptr SignalContext::GetAddress() const { bool SignalContext::IsMemoryAccess() const { auto si = static_cast(siginfo); - return si->si_signo == SIGSEGV; + return si->si_signo == SIGSEGV || si->si_signo == SIGBUS; } int SignalContext::GetType() const { @@ -363,10 +365,18 @@ int GetNamedMappingFd(const char *name, uptr size, int *flags) { CHECK(internal_strlen(name) < sizeof(shmname) - 10); internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]", internal_getpid(), name); + int o_cloexec = 0; +#if defined(O_CLOEXEC) + o_cloexec = O_CLOEXEC; +#endif int fd = ReserveStandardFds( - internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRWXU)); + internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU)); CHECK_GE(fd, 0); int res = internal_ftruncate(fd, size); +#if !defined(O_CLOEXEC) + res = fcntl(fd, F_SETFD, FD_CLOEXEC); + CHECK_EQ(0, res); +#endif CHECK_EQ(0, res); res = internal_unlink(shmname); CHECK_EQ(0, res); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h index 70c71f04d2d34..e1a2b48e5cd81 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h @@ -17,7 +17,6 @@ #include "sanitizer_internal_defs.h" #include "sanitizer_platform_limits_freebsd.h" #include "sanitizer_platform_limits_netbsd.h" -#include "sanitizer_platform_limits_openbsd.h" #include "sanitizer_platform_limits_posix.h" #include "sanitizer_platform_limits_solaris.h" @@ -42,6 +41,7 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset); uptr internal_munmap(void *addr, uptr length); int internal_mprotect(void *addr, uptr length, int prot); +int internal_madvise(uptr addr, uptr length, int advice); // OS uptr internal_filesize(fd_t fd); // -1 on error. @@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data); uptr internal_waitpid(int pid, int *status, int options); int internal_fork(); -fd_t internal_spawn(const char *argv[], pid_t *pid); +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid); int internal_sysctl(const int *name, unsigned int namelen, void *oldp, uptr *oldlenp, const void *newp, uptr newlen); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index 3c0c91e7cac31..623c9e361701a 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -18,7 +18,6 @@ #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_platform_limits_netbsd.h" -#include "sanitizer_platform_limits_openbsd.h" #include "sanitizer_platform_limits_posix.h" #include "sanitizer_platform_limits_solaris.h" #include "sanitizer_posix.h" @@ -61,27 +60,24 @@ void ReleaseMemoryPagesToOS(uptr beg, uptr end) { uptr beg_aligned = RoundUpTo(beg, page_size); uptr end_aligned = RoundDownTo(end, page_size); if (beg_aligned < end_aligned) - // In the default Solaris compilation environment, madvise() is declared - // to take a caddr_t arg; casting it to void * results in an invalid - // conversion error, so use char * instead. - madvise((char *)beg_aligned, end_aligned - beg_aligned, - SANITIZER_MADVISE_DONTNEED); + internal_madvise(beg_aligned, end_aligned - beg_aligned, + SANITIZER_MADVISE_DONTNEED); } void SetShadowRegionHugePageMode(uptr addr, uptr size) { #ifdef MADV_NOHUGEPAGE // May not be defined on old systems. if (common_flags()->no_huge_pages_for_shadow) - madvise((char *)addr, size, MADV_NOHUGEPAGE); + internal_madvise(addr, size, MADV_NOHUGEPAGE); else - madvise((char *)addr, size, MADV_HUGEPAGE); + internal_madvise(addr, size, MADV_HUGEPAGE); #endif // MADV_NOHUGEPAGE } bool DontDumpShadowMemory(uptr addr, uptr length) { #if defined(MADV_DONTDUMP) - return madvise((char *)addr, length, MADV_DONTDUMP) == 0; + return internal_madvise(addr, length, MADV_DONTDUMP) == 0; #elif defined(MADV_NOCORE) - return madvise((char *)addr, length, MADV_NOCORE) == 0; + return internal_madvise(addr, length, MADV_NOCORE) == 0; #else return true; #endif // MADV_DONTDUMP @@ -436,7 +432,8 @@ void AdjustStackSize(void *attr_) { #endif // !SANITIZER_GO pid_t StartSubprocess(const char *program, const char *const argv[], - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, + fd_t stderr_fd) { auto file_closer = at_scope_exit([&] { if (stdin_fd != kInvalidFd) { internal_close(stdin_fd); @@ -479,7 +476,8 @@ pid_t StartSubprocess(const char *program, const char *const argv[], for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); - execv(program, const_cast(&argv[0])); + internal_execve(program, const_cast(&argv[0]), + const_cast(envp)); internal__exit(1); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h index d0e5245f84dab..a56640db43e8a 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h @@ -15,18 +15,19 @@ #include "sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS +#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ + SANITIZER_MAC || SANITIZER_SOLARIS || \ + SANITIZER_FUCHSIA #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" +#include "sanitizer_fuchsia.h" #include "sanitizer_linux.h" #include "sanitizer_mac.h" #include "sanitizer_mutex.h" namespace __sanitizer { - // Memory protection masks. static const uptr kProtectionRead = 1; static const uptr kProtectionWrite = 2; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp index 02ff7c0e91a86..1f489b71ad998 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp @@ -7,11 +7,11 @@ //===----------------------------------------------------------------------===// // // Information about the process mappings -// (FreeBSD, OpenBSD and NetBSD-specific parts). +// (FreeBSD and NetBSD-specific parts). //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD #include "sanitizer_common.h" #if SANITIZER_FREEBSD #include "sanitizer_freebsd.h" @@ -28,11 +28,6 @@ #endif #include -#if SANITIZER_OPENBSD -#define KVME_PROT_READ KVE_PROT_READ -#define KVME_PROT_WRITE KVE_PROT_WRITE -#define KVME_PROT_EXEC KVE_PROT_EXEC -#endif // Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode. #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) @@ -51,10 +46,6 @@ void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { KERN_PROC, KERN_PROC_VMMAP, getpid() -#elif SANITIZER_OPENBSD - CTL_KERN, - KERN_PROC_VMMAP, - getpid() #elif SANITIZER_NETBSD CTL_VM, VM_PROC, @@ -71,28 +62,12 @@ void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { CHECK_EQ(Err, 0); CHECK_GT(Size, 0); -#if !SANITIZER_OPENBSD size_t MmapedSize = Size * 4 / 3; void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()"); Size = MmapedSize; Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0); CHECK_EQ(Err, 0); proc_maps->data = (char *)VmMap; -#else - size_t PageSize = GetPageSize(); - size_t MmapedSize = Size; - MmapedSize = ((MmapedSize - 1) / PageSize + 1) * PageSize; - char *Mem = (char *)MmapOrDie(MmapedSize, "ReadProcMaps()"); - Size = 2 * Size + 10 * sizeof(struct kinfo_vmentry); - if (Size > 0x10000) - Size = 0x10000; - Size = (Size / sizeof(struct kinfo_vmentry)) * sizeof(struct kinfo_vmentry); - Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), Mem, &Size, NULL, 0); - CHECK_EQ(Err, 0); - MmapedSize = Size; - proc_maps->data = Mem; -#endif - proc_maps->mmaped_size = MmapedSize; proc_maps->len = Size; } @@ -117,13 +92,11 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0) segment->protection |= kProtectionExecute; -#if !SANITIZER_OPENBSD if (segment->filename != NULL && segment->filename_size > 0) { internal_snprintf(segment->filename, Min(segment->filename_size, (uptr)PATH_MAX), "%s", VmEntry->kve_path); } -#endif #if SANITIZER_FREEBSD data_.current += VmEntry->kve_structsize; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp index e0cb47f8ca9a1..f2cfcffaf4764 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp @@ -12,7 +12,7 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS + SANITIZER_SOLARIS #include "sanitizer_common.h" #include "sanitizer_placement_new.h" diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_fuchsia.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_fuchsia.cpp new file mode 100644 index 0000000000000..cc3e9be06458e --- /dev/null +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_fuchsia.cpp @@ -0,0 +1,80 @@ +//===-- sanitizer_procmaps_fuchsia.cpp +//----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (Fuchsia-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_FUCHSIA +#include +#include + +#include "sanitizer_common.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +// The cache flag is ignored on Fuchsia because a process can always get this +// information via its process-self handle. +MemoryMappingLayout::MemoryMappingLayout(bool) { Reset(); } + +void MemoryMappingLayout::Reset() { + data_.data.clear(); + data_.current = 0; + + size_t count; + zx_status_t status = _zx_object_get_info( + _zx_process_self(), ZX_INFO_PROCESS_MAPS, nullptr, 0, nullptr, &count); + if (status != ZX_OK) { + return; + } + + size_t filled; + do { + data_.data.resize(count); + status = _zx_object_get_info( + _zx_process_self(), ZX_INFO_PROCESS_MAPS, data_.data.data(), + count * sizeof(zx_info_maps_t), &filled, &count); + if (status != ZX_OK) { + data_.data.clear(); + return; + } + } while (filled < count); +} + +MemoryMappingLayout::~MemoryMappingLayout() {} + +bool MemoryMappingLayout::Error() const { return data_.data.empty(); } + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + while (data_.current < data_.data.size()) { + const auto &entry = data_.data[data_.current++]; + if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) { + segment->start = entry.base; + segment->end = entry.base + entry.size; + segment->offset = entry.u.mapping.vmo_offset; + const auto flags = entry.u.mapping.mmu_flags; + segment->protection = + ((flags & ZX_VM_PERM_READ) ? kProtectionRead : 0) | + ((flags & ZX_VM_PERM_WRITE) ? kProtectionWrite : 0) | + ((flags & ZX_VM_PERM_EXECUTE) ? kProtectionExecute : 0); + if (segment->filename && segment->filename_size > 0) { + uptr len = Min(sizeof(entry.name), segment->filename_size) - 1; + internal_strncpy(segment->filename, entry.name, len); + segment->filename[len] = 0; + } + return true; + } + } + return false; +} + +} // namespace __sanitizer + +#endif // SANITIZER_FUCHSIA diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp index 8793423a60178..bf813f235bb7a 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp @@ -9,13 +9,13 @@ // Information about the process mappings (Solaris-specific parts). //===----------------------------------------------------------------------===// +// Before Solaris 11.4, doesn't work in a largefile environment. +#undef _FILE_OFFSET_BITS #include "sanitizer_platform.h" #if SANITIZER_SOLARIS #include "sanitizer_common.h" #include "sanitizer_procmaps.h" -// Before Solaris 11.4, doesn't work in a largefile environment. -#undef _FILE_OFFSET_BITS #include #include @@ -35,7 +35,8 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; if (data_.current >= last) return false; - prxmap_t *xmapentry = (prxmap_t*)data_.current; + prxmap_t *xmapentry = + const_cast(reinterpret_cast(data_.current)); segment->start = (uptr)xmapentry->pr_vaddr; segment->end = (uptr)(xmapentry->pr_vaddr + xmapentry->pr_size); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h new file mode 100644 index 0000000000000..a288068bf9438 --- /dev/null +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h @@ -0,0 +1,23 @@ +//===-- sanitizer_ptrauth.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PTRAUTH_H +#define SANITIZER_PTRAUTH_H + +#if __has_feature(ptrauth_calls) +#include +#else +// Copied from +#define ptrauth_strip(__value, __key) __value +#define ptrauth_auth_data(__value, __old_key, __old_data) __value +#define ptrauth_string_discriminator(__string) ((int)0) +#endif + +#define STRIP_PC(pc) ((uptr)ptrauth_strip(pc, 0)) + +#endif // SANITIZER_PTRAUTH_H diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_rtems.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_rtems.cpp index 0d2576c00ab3c..d58bd08fb1a89 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_rtems.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_rtems.cpp @@ -49,6 +49,10 @@ uptr internal_getpid() { return getpid(); } +int internal_dlinfo(void *handle, int request, void *p) { + UNIMPLEMENTED(); +} + bool FileExists(const char *filename) { struct stat st; if (stat(filename, &st)) @@ -104,8 +108,6 @@ void SetAlternateSignalStack() {} void UnsetAlternateSignalStack() {} void InitTlsSize() {} -void PrintModuleMap() {} - void SignalContext::DumpAllRegisters(void *context) {} const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index 68d9eb65968dd..cefb870f7e258 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -53,7 +53,10 @@ INTERCEPTOR(uptr, signal, int signum, uptr handler) { INTERCEPTOR(int, sigaction_symname, int signum, const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) { - if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) { + if (!oldact) return 0; + act = nullptr; + } SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); } #define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction_symname) diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_solaris.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_solaris.cpp index 035f2d0ca292a..8789dcd10a954 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_solaris.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_solaris.cpp @@ -74,6 +74,20 @@ DECLARE__REAL_AND_INTERNAL(int, mprotect, void *addr, uptr length, int prot) { return _REAL(mprotect)(addr, length, prot); } +// Illumos' declaration of madvise cannot be made visible if _XOPEN_SOURCE +// is defined as g++ does on Solaris. +// +// This declaration is consistent with Solaris 11.4. Both Illumos and Solaris +// versions older than 11.4 declared madvise with a caddr_t as the first +// argument, but we don't currently support Solaris versions older than 11.4, +// and as mentioned above the declaration is not visible on Illumos so we can +// use any declaration we like on Illumos. +extern "C" int madvise(void *, size_t, int); + +int internal_madvise(uptr addr, uptr length, int advice) { + return madvise((void *)addr, length, advice); +} + DECLARE__REAL_AND_INTERNAL(uptr, close, fd_t fd) { return _REAL(close)(fd); } @@ -146,10 +160,6 @@ DECLARE__REAL_AND_INTERNAL(uptr, sched_yield, void) { return sched_yield(); } -DECLARE__REAL_AND_INTERNAL(void, _exit, int exitcode) { - _exit(exitcode); -} - DECLARE__REAL_AND_INTERNAL(uptr, execve, const char *filename, char *const argv[], char *const envp[]) { return _REAL(execve)(filename, argv, envp); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp index 30073a96ceebd..44a95214e38bf 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp @@ -115,6 +115,12 @@ void StackDepotUnlockAll() { theDepot.UnlockAll(); } +void StackDepotPrintAll() { +#if !SANITIZER_GO + theDepot.PrintAll(); +#endif +} + bool StackDepotReverseMap::IdDescPair::IdComparator( const StackDepotReverseMap::IdDescPair &a, const StackDepotReverseMap::IdDescPair &b) { @@ -139,8 +145,7 @@ StackTrace StackDepotReverseMap::Get(u32 id) { if (!map_.size()) return StackTrace(); IdDescPair pair = {id, nullptr}; - uptr idx = - InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator); + uptr idx = InternalLowerBound(map_, pair, IdDescPair::IdComparator); if (idx > map_.size() || map_[idx].id != id) return StackTrace(); return map_[idx].desc->load(); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h index bf29cb9a006e9..0e26c1fc37c49 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h @@ -41,6 +41,7 @@ StackTrace StackDepotGet(u32 id); void StackDepotLockAll(); void StackDepotUnlockAll(); +void StackDepotPrintAll(); // Instantiating this class creates a snapshot of StackDepot which can be // efficiently queried with StackDepotGet(). You can use it concurrently with diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h index ef1b4f7f70555..1af2c1892eff7 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h @@ -13,9 +13,11 @@ #ifndef SANITIZER_STACKDEPOTBASE_H #define SANITIZER_STACKDEPOTBASE_H +#include + +#include "sanitizer_atomic.h" #include "sanitizer_internal_defs.h" #include "sanitizer_mutex.h" -#include "sanitizer_atomic.h" #include "sanitizer_persistent_allocator.h" namespace __sanitizer { @@ -34,6 +36,7 @@ class StackDepotBase { void LockAll(); void UnlockAll(); + void PrintAll(); private: static Node *find(Node *s, args_type args, u32 hash); @@ -172,6 +175,21 @@ void StackDepotBase::UnlockAll() { } } +template +void StackDepotBase::PrintAll() { + for (int i = 0; i < kTabSize; ++i) { + atomic_uintptr_t *p = &tab[i]; + lock(p); + uptr v = atomic_load(p, memory_order_relaxed); + Node *s = (Node *)(v & ~1UL); + for (; s; s = s->link) { + Printf("Stack for id %u:\n", s->id); + s->load().Print(); + } + unlock(p, s); + } +} + } // namespace __sanitizer #endif // SANITIZER_STACKDEPOTBASE_H diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp index 7029da649eb86..d84d9c9fba93c 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp @@ -10,9 +10,11 @@ // run-time libraries. //===----------------------------------------------------------------------===// +#include "sanitizer_stacktrace.h" + #include "sanitizer_common.h" #include "sanitizer_flags.h" -#include "sanitizer_stacktrace.h" +#include "sanitizer_platform.h" namespace __sanitizer { @@ -21,6 +23,28 @@ uptr StackTrace::GetNextInstructionPc(uptr pc) { return pc + 8; #elif defined(__powerpc__) || defined(__arm__) || defined(__aarch64__) return pc + 4; +#elif SANITIZER_RISCV64 + // Current check order is 4 -> 2 -> 6 -> 8 + u8 InsnByte = *(u8 *)(pc); + if (((InsnByte & 0x3) == 0x3) && ((InsnByte & 0x1c) != 0x1c)) { + // xxxxxxxxxxxbbb11 | 32 bit | bbb != 111 + return pc + 4; + } + if ((InsnByte & 0x3) != 0x3) { + // xxxxxxxxxxxxxxaa | 16 bit | aa != 11 + return pc + 2; + } + // RISC-V encoding allows instructions to be up to 8 bytes long + if ((InsnByte & 0x3f) == 0x1f) { + // xxxxxxxxxx011111 | 48 bit | + return pc + 6; + } + if ((InsnByte & 0x7f) == 0x3f) { + // xxxxxxxxx0111111 | 64 bit | + return pc + 8; + } + // bail-out if could not figure out the instruction size + return 0; #else return pc + 1; #endif @@ -96,6 +120,9 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, uhwptr pc1 = caller_frame[2]; #elif defined(__s390__) uhwptr pc1 = frame[14]; +#elif defined(__riscv) + // frame[-1] contains the return address + uhwptr pc1 = frame[-1]; #else uhwptr pc1 = frame[1]; #endif @@ -108,7 +135,13 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, trace_buffer[size++] = (uptr) pc1; } bottom = (uptr)frame; - frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom); +#if defined(__riscv) + // frame[-2] contain fp of the previous frame + uptr new_bp = (uptr)frame[-2]; +#else + uptr new_bp = (uptr)frame[0]; +#endif + frame = GetCanonicFrame(new_bp, stack_top, bottom); } } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h index ab71cb6a86a0b..03d4d2dd1568e 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -13,6 +13,7 @@ #define SANITIZER_STACKTRACE_H #include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" namespace __sanitizer { @@ -24,8 +25,6 @@ static const u32 kStackTraceMax = 256; # define SANITIZER_CAN_FAST_UNWIND 0 #elif SANITIZER_WINDOWS # define SANITIZER_CAN_FAST_UNWIND 0 -#elif SANITIZER_OPENBSD -# define SANITIZER_CAN_FAST_UNWIND 0 #else # define SANITIZER_CAN_FAST_UNWIND 1 #endif @@ -33,7 +32,7 @@ static const u32 kStackTraceMax = 256; // Fast unwind is the only option on Mac for now; we will need to // revisit this macro when slow unwind works on Mac, see // https://github.com/google/sanitizers/issues/137 -#if SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN +#if SANITIZER_MAC || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN # define SANITIZER_CAN_SLOW_UNWIND 0 #else # define SANITIZER_CAN_SLOW_UNWIND 1 @@ -71,8 +70,6 @@ struct StackTrace { static uptr GetCurrentPc(); static inline uptr GetPreviousInstructionPc(uptr pc); static uptr GetNextInstructionPc(uptr pc); - typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer, - int out_size); }; // Performance-critical, must be in the header. @@ -88,6 +85,14 @@ uptr StackTrace::GetPreviousInstructionPc(uptr pc) { return pc - 4; #elif defined(__sparc__) || defined(__mips__) return pc - 8; +#elif SANITIZER_RISCV64 + // RV-64 has variable instruciton length... + // C extentions gives us 2-byte instructoins + // RV-64 has 4-byte instructions + // + RISCV architecture allows instructions up to 8 bytes + // It seems difficult to figure out the exact instruction length - + // pc - 2 seems like a safe option for the purposes of stack tracing + return pc - 2; #else return pc - 1; #endif @@ -146,9 +151,17 @@ struct BufferedStackTrace : public StackTrace { friend class FastUnwindTest; }; +#if defined(__s390x__) +static const uptr kFrameSize = 160; +#elif defined(__s390__) +static const uptr kFrameSize = 96; +#else +static const uptr kFrameSize = 2 * sizeof(uhwptr); +#endif + // Check if given pointer points into allocated stack area. static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) { - return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr); + return frame > stack_bottom && frame < stack_top - kFrameSize; } } // namespace __sanitizer diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp index 2559349319b34..d0ef5f31547fa 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp @@ -26,6 +26,7 @@ void StackTrace::Print() const { InternalScopedString frame_desc(GetPageSizeCached() * 2); InternalScopedString dedup_token(GetPageSizeCached()); int dedup_frames = common_flags()->dedup_token_length; + bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format); uptr frame_num = 0; for (uptr i = 0; i < size && trace[i]; i++) { #if !SANITIZER_EMSCRIPTEN @@ -37,12 +38,17 @@ void StackTrace::Print() const { // addresses are not return addresses. uptr pc = trace[i]; #endif - SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc); + SymbolizedStack *frames; + if (symbolize) + frames = Symbolizer::GetOrInit()->SymbolizePC(pc); + else + frames = SymbolizedStack::New(pc); CHECK(frames); for (SymbolizedStack *cur = frames; cur; cur = cur->next) { frame_desc.clear(); RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++, - cur->info, common_flags()->symbolize_vs_style, + cur->info.address, symbolize ? &cur->info : nullptr, + common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix); Printf("%s\n", frame_desc.data()); if (dedup_frames-- > 0) { @@ -114,7 +120,12 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, uptr out_buf_size) { if (!out_buf_size) return; pc = StackTrace::GetPreviousInstructionPc(pc); - SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); + SymbolizedStack *frame; + bool symbolize = RenderNeedsSymbolization(fmt); + if (symbolize) + frame = Symbolizer::GetOrInit()->SymbolizePC(pc); + else + frame = SymbolizedStack::New(pc); if (!frame) { internal_strncpy(out_buf, "", out_buf_size); out_buf[out_buf_size - 1] = 0; @@ -127,7 +138,8 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, for (SymbolizedStack *cur = frame; cur && out_buf < out_end; cur = cur->next) { frame_desc.clear(); - RenderFrame(&frame_desc, fmt, frame_num++, cur->info, + RenderFrame(&frame_desc, fmt, frame_num++, cur->info.address, + symbolize ? &cur->info : nullptr, common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix); if (!frame_desc.length()) @@ -140,6 +152,7 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf, } CHECK(out_buf <= out_end); *out_buf = 0; + frame->ClearAll(); } SANITIZER_INTERFACE_ATTRIBUTE diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp index 150ff475316bd..c998322d39441 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp @@ -107,8 +107,14 @@ static const char *DemangleFunctionName(const char *function) { static const char kDefaultFormat[] = " #%n %p %F %L"; void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, - const AddressInfo &info, bool vs_style, + uptr address, const AddressInfo *info, bool vs_style, const char *strip_path_prefix, const char *strip_func_prefix) { + // info will be null in the case where symbolization is not needed for the + // given format. This ensures that the code below will get a hard failure + // rather than print incorrect information in case RenderNeedsSymbolization + // ever ends up out of sync with this function. If non-null, the addresses + // should match. + CHECK(!info || address == info->address); if (0 == internal_strcmp(format, "DEFAULT")) format = kDefaultFormat; for (const char *p = format; *p != '\0'; p++) { @@ -126,71 +132,70 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, buffer->append("%zu", frame_no); break; case 'p': - buffer->append("0x%zx", info.address); + buffer->append("0x%zx", address); break; case 'm': - buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix)); + buffer->append("%s", StripPathPrefix(info->module, strip_path_prefix)); break; case 'o': - buffer->append("0x%zx", info.module_offset); + buffer->append("0x%zx", info->module_offset); break; case 'f': - buffer->append("%s", - DemangleFunctionName( - StripFunctionName(info.function, strip_func_prefix))); + buffer->append("%s", DemangleFunctionName(StripFunctionName( + info->function, strip_func_prefix))); break; case 'q': - buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown - ? info.function_offset + buffer->append("0x%zx", info->function_offset != AddressInfo::kUnknown + ? info->function_offset : 0x0); break; case 's': - buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix)); + buffer->append("%s", StripPathPrefix(info->file, strip_path_prefix)); break; case 'l': - buffer->append("%d", info.line); + buffer->append("%d", info->line); break; case 'c': - buffer->append("%d", info.column); + buffer->append("%d", info->column); break; // Smarter special cases. case 'F': // Function name and offset, if file is unknown. - if (info.function) { - buffer->append("in %s", - DemangleFunctionName( - StripFunctionName(info.function, strip_func_prefix))); - if (!info.file && info.function_offset != AddressInfo::kUnknown) - buffer->append("+0x%zx", info.function_offset); + if (info->function) { + buffer->append("in %s", DemangleFunctionName(StripFunctionName( + info->function, strip_func_prefix))); + if (!info->file && info->function_offset != AddressInfo::kUnknown) + buffer->append("+0x%zx", info->function_offset); } break; case 'S': // File/line information. - RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style, - strip_path_prefix); + RenderSourceLocation(buffer, info->file, info->line, info->column, + vs_style, strip_path_prefix); break; case 'L': // Source location, or module location. - if (info.file) { - RenderSourceLocation(buffer, info.file, info.line, info.column, + if (info->file) { + RenderSourceLocation(buffer, info->file, info->line, info->column, vs_style, strip_path_prefix); - } else if (info.module) { - RenderModuleLocation(buffer, info.module, info.module_offset, - info.module_arch, strip_path_prefix); + } else if (info->module) { + RenderModuleLocation(buffer, info->module, info->module_offset, + info->module_arch, strip_path_prefix); } else { buffer->append("()"); } break; case 'M': // Module basename and offset, or PC. - if (info.address & kExternalPCBit) - {} // There PCs are not meaningful. - else if (info.module) + if (address & kExternalPCBit) { + // There PCs are not meaningful. + } else if (info->module) { // Always strip the module name for %M. - RenderModuleLocation(buffer, StripModuleName(info.module), - info.module_offset, info.module_arch, ""); - else - buffer->append("(%p)", (void *)info.address); + RenderModuleLocation(buffer, StripModuleName(info->module), + info->module_offset, info->module_arch, ""); + } else { + buffer->append("(%p)", (void *)address); + } break; default: Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p, @@ -200,6 +205,29 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, } } +bool RenderNeedsSymbolization(const char *format) { + if (0 == internal_strcmp(format, "DEFAULT")) + format = kDefaultFormat; + for (const char *p = format; *p != '\0'; p++) { + if (*p != '%') + continue; + p++; + switch (*p) { + case '%': + break; + case 'n': + // frame_no + break; + case 'p': + // address + break; + default: + return true; + } + } + return false; +} + void RenderData(InternalScopedString *buffer, const char *format, const DataInfo *DI, const char *strip_path_prefix) { for (const char *p = format; *p != '\0'; p++) { diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h index f7f7629f773f9..96119b2ee9e9f 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h @@ -47,10 +47,12 @@ namespace __sanitizer { // module+offset if it is known, or () string. // %M - prints module basename and offset, if it is known, or PC. void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, - const AddressInfo &info, bool vs_style, + uptr address, const AddressInfo *info, bool vs_style, const char *strip_path_prefix = "", const char *strip_func_prefix = ""); +bool RenderNeedsSymbolization(const char *format); + void RenderSourceLocation(InternalScopedString *buffer, const char *file, int line, int column, bool vs_style, const char *strip_path_prefix); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h index 4e42400571423..7891c1081fe71 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h @@ -32,20 +32,21 @@ class SuspendedThreadsList { // Can't declare pure virtual functions in sanitizer runtimes: // __cxa_pure_virtual might be unavailable. Use UNIMPLEMENTED() instead. - virtual PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const { + virtual PtraceRegistersStatus GetRegistersAndSP( + uptr index, InternalMmapVector *buffer, uptr *sp) const { UNIMPLEMENTED(); } - // The buffer in GetRegistersAndSP should be at least this big. - virtual uptr RegisterCount() const { UNIMPLEMENTED(); } virtual uptr ThreadCount() const { UNIMPLEMENTED(); } virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); } + protected: + ~SuspendedThreadsList() {} + private: // Prohibit copy and assign. - SuspendedThreadsList(const SuspendedThreadsList&); - void operator=(const SuspendedThreadsList&); + SuspendedThreadsList(const SuspendedThreadsList &) = delete; + void operator=(const SuspendedThreadsList &) = delete; }; typedef void (*StopTheWorldCallback)( diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp new file mode 100644 index 0000000000000..91bf19e40dad8 --- /dev/null +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp @@ -0,0 +1,43 @@ +//===-- sanitizer_stoptheworld_fuchsia.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// See sanitizer_stoptheworld.h for details. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FUCHSIA + +#include + +#include "sanitizer_stoptheworld.h" +#include "sanitizer_stoptheworld_fuchsia.h" + +namespace __sanitizer { + +// The Fuchsia implementation stops the world but doesn't offer a real +// SuspendedThreadsList argument. This is enough for ASan's use case, +// and LSan does not use this API on Fuchsia. +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + struct Params { + StopTheWorldCallback callback; + void *argument; + } params = {callback, argument}; + __sanitizer_memory_snapshot( + nullptr, nullptr, nullptr, nullptr, + [](zx_status_t, void *data) { + auto params = reinterpret_cast(data); + params->callback(SuspendedThreadsListFuchsia(), params->argument); + }, + ¶ms); +} + +} // namespace __sanitizer + +#endif // SANITIZER_FUCHSIA diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.h new file mode 100644 index 0000000000000..6d9ead6050865 --- /dev/null +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.h @@ -0,0 +1,20 @@ +//===-- sanitizer_stoptheworld_fuchsia.h ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_STOPTHEWORLD_FUCHSIA_H +#define SANITIZER_STOPTHEWORLD_FUCHSIA_H + +#include "sanitizer_stoptheworld.h" + +namespace __sanitizer { + +class SuspendedThreadsListFuchsia final : public SuspendedThreadsList {}; + +} // namespace __sanitizer + +#endif // SANITIZER_STOPTHEWORLD_FUCHSIA_H diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp index 651d5056dd9d5..53cfddcfbe0be 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp @@ -13,10 +13,10 @@ #include "sanitizer_platform.h" -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \ - defined(__aarch64__) || defined(__powerpc64__) || \ - defined(__s390__) || defined(__i386__) || \ - defined(__arm__)) +#if SANITIZER_LINUX && \ + (defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \ + defined(__arm__) || SANITIZER_RISCV64) #include "sanitizer_stoptheworld.h" @@ -31,7 +31,7 @@ #include // for pid_t #include // for iovec #include // for NT_PRSTATUS -#if defined(__aarch64__) && !SANITIZER_ANDROID +#if (defined(__aarch64__) || SANITIZER_RISCV64) && !SANITIZER_ANDROID // GLIBC 2.20+ sys/user does not include asm/ptrace.h # include #endif @@ -85,18 +85,18 @@ namespace __sanitizer { -class SuspendedThreadsListLinux : public SuspendedThreadsList { +class SuspendedThreadsListLinux final : public SuspendedThreadsList { public: SuspendedThreadsListLinux() { thread_ids_.reserve(1024); } - tid_t GetThreadID(uptr index) const; - uptr ThreadCount() const; + tid_t GetThreadID(uptr index) const override; + uptr ThreadCount() const override; bool ContainsTid(tid_t thread_id) const; void Append(tid_t tid); - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const; - uptr RegisterCount() const; + PtraceRegistersStatus GetRegistersAndSP(uptr index, + InternalMmapVector *buffer, + uptr *sp) const override; private: InternalMmapVector thread_ids_; @@ -485,6 +485,16 @@ typedef user_regs_struct regs_struct; #else #define REG_SP rsp #endif +#define ARCH_IOVEC_FOR_GETREGSET +// Support ptrace extensions even when compiled without required kernel support +#ifndef NT_X86_XSTATE +#define NT_X86_XSTATE 0x202 +#endif +#ifndef PTRACE_GETREGSET +#define PTRACE_GETREGSET 0x4204 +#endif +// Compiler may use FP registers to store pointers. +static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET}; #elif defined(__powerpc__) || defined(__powerpc64__) typedef pt_regs regs_struct; @@ -501,11 +511,21 @@ typedef struct user regs_struct; #elif defined(__aarch64__) typedef struct user_pt_regs regs_struct; #define REG_SP sp +static constexpr uptr kExtraRegs[] = {0}; +#define ARCH_IOVEC_FOR_GETREGSET + +#elif SANITIZER_RISCV64 +typedef struct user_regs_struct regs_struct; +// sys/ucontext.h already defines REG_SP as 2. Undefine it first. +#undef REG_SP +#define REG_SP sp +static constexpr uptr kExtraRegs[] = {0}; #define ARCH_IOVEC_FOR_GETREGSET #elif defined(__s390__) typedef _user_regs_struct regs_struct; #define REG_SP gprs[15] +static constexpr uptr kExtraRegs[] = {0}; #define ARCH_IOVEC_FOR_GETREGSET #else @@ -533,24 +553,58 @@ void SuspendedThreadsListLinux::Append(tid_t tid) { } PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP( - uptr index, uptr *buffer, uptr *sp) const { + uptr index, InternalMmapVector *buffer, uptr *sp) const { pid_t tid = GetThreadID(index); - regs_struct regs; + constexpr uptr uptr_sz = sizeof(uptr); int pterrno; #ifdef ARCH_IOVEC_FOR_GETREGSET - struct iovec regset_io; - regset_io.iov_base = ®s; - regset_io.iov_len = sizeof(regs_struct); - bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, - (void*)NT_PRSTATUS, (void*)®set_io), - &pterrno); + auto append = [&](uptr regset) { + uptr size = buffer->size(); + // NT_X86_XSTATE requires 64bit alignment. + uptr size_up = RoundUpTo(size, 8 / uptr_sz); + buffer->reserve(Max(1024, size_up)); + struct iovec regset_io; + for (;; buffer->resize(buffer->capacity() * 2)) { + buffer->resize(buffer->capacity()); + uptr available_bytes = (buffer->size() - size_up) * uptr_sz; + regset_io.iov_base = buffer->data() + size_up; + regset_io.iov_len = available_bytes; + bool fail = + internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, + (void *)regset, (void *)®set_io), + &pterrno); + if (fail) { + VReport(1, "Could not get regset %p from thread %d (errno %d).\n", + (void *)regset, tid, pterrno); + buffer->resize(size); + return false; + } + + // Far enough from the buffer size, no need to resize and repeat. + if (regset_io.iov_len + 64 < available_bytes) + break; + } + buffer->resize(size_up + RoundUpTo(regset_io.iov_len, uptr_sz) / uptr_sz); + return true; + }; + + buffer->clear(); + bool fail = !append(NT_PRSTATUS); + if (!fail) { + // Accept the first available and do not report errors. + for (uptr regs : kExtraRegs) + if (regs && append(regs)) + break; + } #else - bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, nullptr, - ®s), &pterrno); -#endif - if (isErr) { + buffer->resize(RoundUpTo(sizeof(regs_struct), uptr_sz) / uptr_sz); + bool fail = internal_iserror( + internal_ptrace(PTRACE_GETREGS, tid, nullptr, buffer->data()), &pterrno); + if (fail) VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, pterrno); +#endif + if (fail) { // ESRCH means that the given thread is not suspended or already dead. // Therefore it's unsafe to inspect its data (e.g. walk through stack) and // we should notify caller about this. @@ -558,14 +612,10 @@ PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP( : REGISTERS_UNAVAILABLE; } - *sp = regs.REG_SP; - internal_memcpy(buffer, ®s, sizeof(regs)); + *sp = reinterpret_cast(buffer->data())[0].REG_SP; return REGISTERS_AVAILABLE; } -uptr SuspendedThreadsListLinux::RegisterCount() const { - return sizeof(regs_struct) / sizeof(uptr); -} } // namespace __sanitizer #endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp index 9dffd21ecb7cc..5ec30803b7ade 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp @@ -27,19 +27,19 @@ typedef struct { thread_t thread; } SuspendedThreadInfo; -class SuspendedThreadsListMac : public SuspendedThreadsList { +class SuspendedThreadsListMac final : public SuspendedThreadsList { public: SuspendedThreadsListMac() : threads_(1024) {} - tid_t GetThreadID(uptr index) const; + tid_t GetThreadID(uptr index) const override; thread_t GetThread(uptr index) const; - uptr ThreadCount() const; + uptr ThreadCount() const override; bool ContainsThread(thread_t thread) const; void Append(thread_t thread); - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const; - uptr RegisterCount() const; + PtraceRegistersStatus GetRegistersAndSP(uptr index, + InternalMmapVector *buffer, + uptr *sp) const override; private: InternalMmapVector threads_; @@ -50,7 +50,7 @@ struct RunThreadArgs { void *argument; }; -void RunThread(void *arg) { +void *RunThread(void *arg) { struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg; SuspendedThreadsListMac suspended_threads_list; @@ -59,7 +59,7 @@ void RunThread(void *arg) { kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads); if (err != KERN_SUCCESS) { VReport(1, "Failed to get threads for task (errno %d).\n", err); - return; + return nullptr; } thread_t thread_self = mach_thread_self(); @@ -76,6 +76,7 @@ void RunThread(void *arg) { for (unsigned int i = 0; i < num_suspended; ++i) { thread_resume(suspended_threads_list.GetThread(i)); } + return nullptr; } void StopTheWorld(StopTheWorldCallback callback, void *argument) { @@ -141,7 +142,7 @@ void SuspendedThreadsListMac::Append(thread_t thread) { } PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( - uptr index, uptr *buffer, uptr *sp) const { + uptr index, InternalMmapVector *buffer, uptr *sp) const { thread_t thread = GetThread(index); regs_struct regs; int err; @@ -158,8 +159,13 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( : REGISTERS_UNAVAILABLE; } - internal_memcpy(buffer, ®s, sizeof(regs)); + buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr)); + internal_memcpy(buffer->data(), ®s, sizeof(regs)); +#if defined(__aarch64__) && defined(arm_thread_state64_get_sp) + *sp = arm_thread_state64_get_sp(regs); +#else *sp = regs.SP_REG; +#endif // On x86_64 and aarch64, we must account for the stack redzone, which is 128 // bytes. @@ -168,9 +174,6 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( return REGISTERS_AVAILABLE; } -uptr SuspendedThreadsListMac::RegisterCount() const { - return MACHINE_THREAD_STATE_COUNT; -} } // namespace __sanitizer #endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) || diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp index 1ed21343254d5..9c7cd64255e55 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp @@ -48,7 +48,7 @@ namespace __sanitizer { -class SuspendedThreadsListNetBSD : public SuspendedThreadsList { +class SuspendedThreadsListNetBSD final : public SuspendedThreadsList { public: SuspendedThreadsListNetBSD() { thread_ids_.reserve(1024); } @@ -57,9 +57,9 @@ class SuspendedThreadsListNetBSD : public SuspendedThreadsList { bool ContainsTid(tid_t thread_id) const; void Append(tid_t tid); - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + PtraceRegistersStatus GetRegistersAndSP(uptr index, + InternalMmapVector *buffer, uptr *sp) const; - uptr RegisterCount() const; private: InternalMmapVector thread_ids_; @@ -131,7 +131,7 @@ bool ThreadSuspender::SuspendAllThreads() { pl.pl_lwpid = 0; int val; - while ((val = ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 && + while ((val = internal_ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 && pl.pl_lwpid != 0) { suspended_threads_list_.Append(pl.pl_lwpid); VReport(2, "Appended thread %d in process %d.\n", pl.pl_lwpid, pid_); @@ -335,7 +335,7 @@ void SuspendedThreadsListNetBSD::Append(tid_t tid) { } PtraceRegistersStatus SuspendedThreadsListNetBSD::GetRegistersAndSP( - uptr index, uptr *buffer, uptr *sp) const { + uptr index, InternalMmapVector *buffer, uptr *sp) const { lwpid_t tid = GetThreadID(index); pid_t ppid = internal_getppid(); struct reg regs; @@ -351,14 +351,12 @@ PtraceRegistersStatus SuspendedThreadsListNetBSD::GetRegistersAndSP( } *sp = PTRACE_REG_SP(®s); - internal_memcpy(buffer, ®s, sizeof(regs)); + buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr)); + internal_memcpy(buffer->data(), ®s, sizeof(regs)); return REGISTERS_AVAILABLE; } -uptr SuspendedThreadsListNetBSD::RegisterCount() const { - return sizeof(struct reg) / sizeof(uptr); -} } // namespace __sanitizer #endif diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp index ce2ece5f4d512..0c4b84c767aa1 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp @@ -126,4 +126,10 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() { sym_->end_hook_(); } +void Symbolizer::LateInitializeTools() { + for (auto &tool : tools_) { + tool.LateInitialize(); + } +} + } // namespace __sanitizer diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h index 51648e2d0e8d7..2476b0ea7bf7d 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h @@ -209,6 +209,9 @@ class Symbolizer final { private: const Symbolizer *sym_; }; + + // Calls `LateInitialize()` on all items in `tools_`. + void LateInitializeTools(); }; #ifdef SANITIZER_WINDOWS diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h index c04797dd61b8b..71de1758b3e9c 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -69,6 +69,14 @@ class SymbolizerTool { virtual const char *Demangle(const char *name) { return nullptr; } + + // Called during the LateInitialize phase of Sanitizer initialization. + // Usually this is a safe place to call code that might need to use user + // memory allocators. + virtual void LateInitialize() {} + + protected: + ~SymbolizerTool() {} }; // SymbolizerProcess encapsulates communication between the tool and @@ -80,12 +88,16 @@ class SymbolizerProcess { const char *SendCommand(const char *command); protected: + ~SymbolizerProcess() {} + /// The maximum number of arguments required to invoke a tool process. static const unsigned kArgVMax = 6; // Customizable by subclasses. virtual bool StartSymbolizerSubprocess(); virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); + // Return the environment to run the symbolizer in. + virtual char **GetEnvP() { return GetEnviron(); } private: virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { @@ -121,7 +133,7 @@ class LLVMSymbolizerProcess; // This tool invokes llvm-symbolizer in a subprocess. It should be as portable // as the llvm-symbolizer tool is. -class LLVMSymbolizer : public SymbolizerTool { +class LLVMSymbolizer final : public SymbolizerTool { public: explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h index e2a0f71420f0e..7b039b894b3be 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h @@ -28,7 +28,7 @@ namespace __sanitizer { -class LibbacktraceSymbolizer : public SymbolizerTool { +class LibbacktraceSymbolizer final : public SymbolizerTool { public: static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp index 3b19a6836ec53..710da4c1cecd1 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp @@ -12,6 +12,7 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_internal_defs.h" +#include "sanitizer_platform.h" #include "sanitizer_symbolizer_internal.h" namespace __sanitizer { @@ -39,9 +40,9 @@ const char *ExtractToken(const char *str, const char *delims, char **result) { } const char *ExtractInt(const char *str, const char *delims, int *result) { - char *buff; + char *buff = nullptr; const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { + if (buff) { *result = (int)internal_atoll(buff); } InternalFree(buff); @@ -49,9 +50,9 @@ const char *ExtractInt(const char *str, const char *delims, int *result) { } const char *ExtractUptr(const char *str, const char *delims, uptr *result) { - char *buff; + char *buff = nullptr; const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { + if (buff) { *result = (uptr)internal_atoll(buff); } InternalFree(buff); @@ -59,9 +60,9 @@ const char *ExtractUptr(const char *str, const char *delims, uptr *result) { } const char *ExtractSptr(const char *str, const char *delims, sptr *result) { - char *buff; + char *buff = nullptr; const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { + if (buff) { *result = (sptr)internal_atoll(buff); } InternalFree(buff); @@ -83,7 +84,7 @@ const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { BlockingMutexLock l(&mu_); - const char *module_name; + const char *module_name = nullptr; uptr module_offset; ModuleArch arch; SymbolizedStack *res = SymbolizedStack::New(addr); @@ -103,7 +104,7 @@ SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { BlockingMutexLock l(&mu_); - const char *module_name; + const char *module_name = nullptr; uptr module_offset; ModuleArch arch; if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset, @@ -124,7 +125,7 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { BlockingMutexLock l(&mu_); - const char *module_name; + const char *module_name = nullptr; if (!FindModuleNameAndOffsetForAddress( addr, &module_name, &info->module_offset, &info->module_arch)) return false; @@ -175,7 +176,7 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, uptr *module_offset, ModuleArch *module_arch) { const LoadedModule *module = FindModuleForAddress(address); - if (module == nullptr) + if (!module) return false; *module_name = module->full_name(); *module_offset = address - module->base_address(); @@ -236,7 +237,7 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) { // :: // ... // -class LLVMSymbolizerProcess : public SymbolizerProcess { +class LLVMSymbolizerProcess final : public SymbolizerProcess { public: explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path, /*use_posix_spawn=*/SANITIZER_MAC) {} @@ -258,6 +259,8 @@ class LLVMSymbolizerProcess : public SymbolizerProcess { const char* const kSymbolizerArch = "--default-arch=x86_64"; #elif defined(__i386__) const char* const kSymbolizerArch = "--default-arch=i386"; +#elif SANITIZER_RISCV64 + const char *const kSymbolizerArch = "--default-arch=riscv64"; #elif defined(__aarch64__) const char* const kSymbolizerArch = "--default-arch=arm64"; #elif defined(__arm__) @@ -275,8 +278,8 @@ class LLVMSymbolizerProcess : public SymbolizerProcess { #endif const char *const inline_flag = common_flags()->symbolize_inline_frames - ? "--inlining=true" - : "--inlining=false"; + ? "--inlines" + : "--no-inlines"; int i = 0; argv[i++] = path_to_binary; argv[i++] = inline_flag; @@ -292,7 +295,7 @@ LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator) // Windows, so extract tokens from the right hand side first. The column info is // also optional. static const char *ParseFileLineInfo(AddressInfo *info, const char *str) { - char *file_line_info = 0; + char *file_line_info = nullptr; str = ExtractToken(str, "\n", &file_line_info); CHECK(file_line_info); @@ -323,7 +326,7 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) { bool top_frame = true; SymbolizedStack *last = res; while (true) { - char *function_name = 0; + char *function_name = nullptr; str = ExtractToken(str, "\n", &function_name); CHECK(function_name); if (function_name[0] == '\0') { @@ -402,32 +405,29 @@ bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { AddressInfo *info = &stack->info; const char *buf = FormatAndSendCommand( "CODE", info->module, info->module_offset, info->module_arch); - if (buf) { - ParseSymbolizePCOutput(buf, stack); - return true; - } - return false; + if (!buf) + return false; + ParseSymbolizePCOutput(buf, stack); + return true; } bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { const char *buf = FormatAndSendCommand( "DATA", info->module, info->module_offset, info->module_arch); - if (buf) { - ParseSymbolizeDataOutput(buf, info); - info->start += (addr - info->module_offset); // Add the base address. - return true; - } - return false; + if (!buf) + return false; + ParseSymbolizeDataOutput(buf, info); + info->start += (addr - info->module_offset); // Add the base address. + return true; } bool LLVMSymbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { const char *buf = FormatAndSendCommand( "FRAME", info->module, info->module_offset, info->module_arch); - if (buf) { - ParseSymbolizeFrameOutput(buf, &info->locals); - return true; - } - return false; + if (!buf) + return false; + ParseSymbolizeFrameOutput(buf, &info->locals); + return true; } const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix, @@ -435,21 +435,21 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix, uptr module_offset, ModuleArch arch) { CHECK(module_name); - if (arch == kModuleArchUnknown) { - if (internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n", - command_prefix, module_name, - module_offset) >= static_cast(kBufferSize)) { - Report("WARNING: Command buffer too small"); - return nullptr; - } - } else { - if (internal_snprintf(buffer_, kBufferSize, "%s \"%s:%s\" 0x%zx\n", - command_prefix, module_name, ModuleArchToString(arch), - module_offset) >= static_cast(kBufferSize)) { - Report("WARNING: Command buffer too small"); - return nullptr; - } + int size_needed = 0; + if (arch == kModuleArchUnknown) + size_needed = internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n", + command_prefix, module_name, module_offset); + else + size_needed = internal_snprintf(buffer_, kBufferSize, + "%s \"%s:%s\" 0x%zx\n", command_prefix, + module_name, ModuleArchToString(arch), + module_offset); + + if (size_needed >= static_cast(kBufferSize)) { + Report("WARNING: Command buffer too small"); + return nullptr; } + return symbolizer_process_->SendCommand(buffer_); } @@ -492,16 +492,16 @@ const char *SymbolizerProcess::SendCommand(const char *command) { Report("WARNING: Failed to use and restart external symbolizer!\n"); failed_to_start_ = true; } - return 0; + return nullptr; } const char *SymbolizerProcess::SendCommandImpl(const char *command) { if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd) - return 0; + return nullptr; if (!WriteToSymbolizer(command, internal_strlen(command))) - return 0; + return nullptr; if (!ReadFromSymbolizer(buffer_, kBufferSize)) - return 0; + return nullptr; return buffer_; } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp index f26efe5c50b55..5c25b28b5dc96 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -32,8 +33,15 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { int result = dladdr((const void *)addr, &info); if (!result) return false; - CHECK(addr >= reinterpret_cast(info.dli_saddr)); - stack->info.function_offset = addr - reinterpret_cast(info.dli_saddr); + // Compute offset if possible. `dladdr()` doesn't always ensure that `addr >= + // sym_addr` so only compute the offset when this holds. Failure to find the + // function offset is not treated as a failure because it might still be + // possible to get the symbol name. + uptr sym_addr = reinterpret_cast(info.dli_saddr); + if (addr >= sym_addr) { + stack->info.function_offset = addr - sym_addr; + } + const char *demangled = DemangleSwiftAndCXX(info.dli_sname); if (!demangled) return false; stack->info.function = internal_strdup(demangled); @@ -50,18 +58,65 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { return true; } -class AtosSymbolizerProcess : public SymbolizerProcess { +#define K_ATOS_ENV_VAR "__check_mach_ports_lookup" + +// This cannot live in `AtosSymbolizerProcess` because instances of that object +// are allocated by the internal allocator which under ASan is poisoned with +// kAsanInternalHeapMagic. +static char kAtosMachPortEnvEntry[] = K_ATOS_ENV_VAR "=000000000000000"; + +class AtosSymbolizerProcess final : public SymbolizerProcess { public: - explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) + explicit AtosSymbolizerProcess(const char *path) : SymbolizerProcess(path, /*use_posix_spawn*/ true) { - // Put the string command line argument in the object so that it outlives - // the call to GetArgV. - internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid); + pid_str_[0] = '\0'; + } + + void LateInitialize() { + if (SANITIZER_IOSSIM) { + // `putenv()` may call malloc/realloc so it is only safe to do this + // during LateInitialize() or later (i.e. we can't do this in the + // constructor). We also can't do this in `StartSymbolizerSubprocess()` + // because in TSan we switch allocators when we're symbolizing. + // We use `putenv()` rather than `setenv()` so that we can later directly + // write into the storage without LibC getting involved to change what the + // variable is set to + int result = putenv(kAtosMachPortEnvEntry); + CHECK_EQ(result, 0); + } } private: bool StartSymbolizerSubprocess() override { // Configure sandbox before starting atos process. + + // Put the string command line argument in the object so that it outlives + // the call to GetArgV. + internal_snprintf(pid_str_, sizeof(pid_str_), "%d", internal_getpid()); + + if (SANITIZER_IOSSIM) { + // `atos` in the simulator is restricted in its ability to retrieve the + // task port for the target process (us) so we need to do extra work + // to pass our task port to it. + mach_port_t ports[]{mach_task_self()}; + kern_return_t ret = + mach_ports_register(mach_task_self(), ports, /*count=*/1); + CHECK_EQ(ret, KERN_SUCCESS); + + // Set environment variable that signals to `atos` that it should look + // for our task port. We can't call `setenv()` here because it might call + // malloc/realloc. To avoid that we instead update the + // `mach_port_env_var_entry_` variable with our current PID. + uptr count = internal_snprintf(kAtosMachPortEnvEntry, + sizeof(kAtosMachPortEnvEntry), + K_ATOS_ENV_VAR "=%s", pid_str_); + CHECK_GE(count, sizeof(K_ATOS_ENV_VAR) + internal_strlen(pid_str_)); + // Document our assumption but without calling `getenv()` in normal + // builds. + DCHECK(getenv(K_ATOS_ENV_VAR)); + DCHECK_EQ(internal_strcmp(getenv(K_ATOS_ENV_VAR), pid_str_), 0); + } + return SymbolizerProcess::StartSymbolizerSubprocess(); } @@ -75,7 +130,7 @@ class AtosSymbolizerProcess : public SymbolizerProcess { argv[i++] = path_to_binary; argv[i++] = "-p"; argv[i++] = &pid_str_[0]; - if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) { + if (GetMacosAlignedVersion() == MacosVersion(10, 9)) { // On Mavericks atos prints a deprecation warning which we suppress by // passing -d. The warning isn't present on other OSX versions, even the // newer ones. @@ -85,8 +140,14 @@ class AtosSymbolizerProcess : public SymbolizerProcess { } char pid_str_[16]; + // Space for `\0` in `K_ATOS_ENV_VAR` is reused for `=`. + static_assert(sizeof(kAtosMachPortEnvEntry) == + (sizeof(K_ATOS_ENV_VAR) + sizeof(pid_str_)), + "sizes should match"); }; +#undef K_ATOS_ENV_VAR + static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, char **out_module, char **out_file, uptr *line, uptr *start_address) { @@ -138,7 +199,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, } AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) - : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {} + : process_(new (*allocator) AtosSymbolizerProcess(path)) {} bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { if (!process_) return false; @@ -165,10 +226,10 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { start_address = reinterpret_cast(info.dli_saddr); } - // Only assig to `function_offset` if we were able to get the function's - // start address. - if (start_address != AddressInfo::kUnknown) { - CHECK(addr >= start_address); + // Only assign to `function_offset` if we were able to get the function's + // start address and we got a sensible `start_address` (dladdr doesn't always + // ensure that `addr >= sym_addr`). + if (start_address != AddressInfo::kUnknown && addr >= start_address) { stack->info.function_offset = addr - start_address; } return true; @@ -188,6 +249,8 @@ bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return true; } +void AtosSymbolizer::LateInitialize() { process_->LateInitialize(); } + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h index 68521375e64c4..401d30fa50330 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h @@ -21,7 +21,7 @@ namespace __sanitizer { -class DlAddrSymbolizer : public SymbolizerTool { +class DlAddrSymbolizer final : public SymbolizerTool { public: bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; bool SymbolizeData(uptr addr, DataInfo *info) override; @@ -29,12 +29,13 @@ class DlAddrSymbolizer : public SymbolizerTool { class AtosSymbolizerProcess; -class AtosSymbolizer : public SymbolizerTool { +class AtosSymbolizer final : public SymbolizerTool { public: explicit AtosSymbolizer(const char *path, LowLevelAllocator *allocator); bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; bool SymbolizeData(uptr addr, DataInfo *info) override; + void LateInitialize() override; private: AtosSymbolizerProcess *process_; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp index 57b4d0c9d9613..30cba08ed5390 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp @@ -83,18 +83,23 @@ void RenderData(InternalScopedString *buffer, const char *format, buffer->append(kFormatData, DI->start); } +bool RenderNeedsSymbolization(const char *format) { return false; } + // We don't support the stack_trace_format flag at all. void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no, - const AddressInfo &info, bool vs_style, + uptr address, const AddressInfo *info, bool vs_style, const char *strip_path_prefix, const char *strip_func_prefix) { - buffer->append(kFormatFrame, frame_no, info.address); + CHECK(!RenderNeedsSymbolization(format)); + buffer->append(kFormatFrame, frame_no, address); } Symbolizer *Symbolizer::PlatformInit() { return new (symbolizer_allocator_) Symbolizer({}); } -void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } +void Symbolizer::LateInitialize() { + Symbolizer::GetOrInit()->LateInitializeTools(); +} void StartReportDeadlySignal() {} void ReportDeadlySignal(const SignalContext &sig, u32 tid, diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index 3918348b47bec..ef7635cf792b4 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -78,13 +78,6 @@ static void InitializeSwiftDemangler() { // Attempts to demangle a Swift name. The demangler will return nullptr if a // non-Swift name is passed in. const char *DemangleSwift(const char *name) { - if (!name) return nullptr; - - // Check if we are dealing with a Swift mangled name first. - if (name[0] != '_' || name[1] != 'T') { - return nullptr; - } - if (swift_demangle_f) return swift_demangle_f(name, internal_strlen(name), 0, 0, 0); @@ -151,9 +144,19 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { GetArgV(path_, argv); pid_t pid; + // Report how symbolizer is being launched for debugging purposes. + if (Verbosity() >= 3) { + // Only use `Report` for first line so subsequent prints don't get prefixed + // with current PID. + Report("Launching Symbolizer process: "); + for (unsigned index = 0; index < kArgVMax && argv[index]; ++index) + Printf("%s ", argv[index]); + Printf("\n"); + } + if (use_posix_spawn_) { #if SANITIZER_MAC - fd_t fd = internal_spawn(argv, &pid); + fd_t fd = internal_spawn(argv, const_cast(GetEnvP()), &pid); if (fd == kInvalidFd) { Report("WARNING: failed to spawn external symbolizer (errno: %d)\n", errno); @@ -173,7 +176,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { return false; } - pid = StartSubprocess(path_, argv, /* stdin */ outfd[0], + pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0], /* stdout */ infd[1]); if (pid < 0) { internal_close(infd[0]); @@ -198,7 +201,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { return true; } -class Addr2LineProcess : public SymbolizerProcess { +class Addr2LineProcess final : public SymbolizerProcess { public: Addr2LineProcess(const char *path, const char *module_name) : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {} @@ -258,7 +261,7 @@ bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer, output_terminator_, kTerminatorLen); } -class Addr2LinePool : public SymbolizerTool { +class Addr2LinePool final : public SymbolizerTool { public: explicit Addr2LinePool(const char *addr2line_path, LowLevelAllocator *allocator) @@ -311,9 +314,10 @@ class Addr2LinePool : public SymbolizerTool { #if SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset, - char *Buffer, int MaxLength); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool +__sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset, + char *Buffer, int MaxLength, + bool SymbolizeInlineFrames); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset, char *Buffer, int MaxLength); @@ -324,7 +328,7 @@ int __sanitizer_symbolize_demangle(const char *Name, char *Buffer, int MaxLength); } // extern "C" -class InternalSymbolizer : public SymbolizerTool { +class InternalSymbolizer final : public SymbolizerTool { public: static InternalSymbolizer *get(LowLevelAllocator *alloc) { if (__sanitizer_symbolize_code != 0 && @@ -336,7 +340,8 @@ class InternalSymbolizer : public SymbolizerTool { bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { bool result = __sanitizer_symbolize_code( - stack->info.module, stack->info.module_offset, buffer_, kBufferSize); + stack->info.module, stack->info.module_offset, buffer_, kBufferSize, + common_flags()->symbolize_inline_frames); if (result) ParseSymbolizePCOutput(buffer_, stack); return result; } @@ -382,7 +387,7 @@ class InternalSymbolizer : public SymbolizerTool { }; #else // SANITIZER_SUPPORTS_WEAK_HOOKS -class InternalSymbolizer : public SymbolizerTool { +class InternalSymbolizer final : public SymbolizerTool { public: static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; } }; @@ -478,7 +483,7 @@ Symbolizer *Symbolizer::PlatformInit() { } void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); + Symbolizer::GetOrInit()->LateInitializeTools(); InitializeSwiftDemangler(); } diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp index 4783459fba52a..1e3d16141b80a 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp @@ -33,7 +33,8 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info, if (!common_flags()->print_summary) return; InternalScopedString buff(kMaxSummaryLength); buff.append("%s ", error_type); - RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, + RenderFrame(&buff, "%L %F", 0, info.address, &info, + common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix); ReportErrorSummary(buff.data(), alt_tool_name); } @@ -42,7 +43,7 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info, #if SANITIZER_EMSCRIPTEN #include -static INLINE bool ReportSupportsColors() { +static inline bool ReportSupportsColors() { return !!EM_ASM_INT({ var setting = Module['printWithColors']; if (setting != null) { @@ -61,14 +62,14 @@ bool ReportFile::SupportsColors() { return SupportsColoredOutput(fd); } -static INLINE bool ReportSupportsColors() { +static inline bool ReportSupportsColors() { return report_file.SupportsColors(); } #else // SANITIZER_FUCHSIA // Fuchsia's logs always go through post-processing that handles colorization. -static INLINE bool ReportSupportsColors() { return true; } +static inline bool ReportSupportsColors() { return true; } #endif // SANITIZER_EMSCRIPTEN, !SANITIZER_FUCHSIA @@ -224,7 +225,7 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, Report("The signal is caused by a %s memory access.\n", access_type); if (!sig.is_true_faulting_addr) Report("Hint: this fault was caused by a dereference of a high value " - "address (see register values below). Dissassemble the provided " + "address (see register values below). Disassemble the provided " "pc to learn which register was used.\n"); else if (sig.addr < GetPageSizeCached()) Report("Hint: address points to the zero page.\n"); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp index 2808779156edd..7db7d3b0eb9d8 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp @@ -33,7 +33,7 @@ decltype(::UnDecorateSymbolName) *UnDecorateSymbolName; namespace { -class WinSymbolizerTool : public SymbolizerTool { +class WinSymbolizerTool final : public SymbolizerTool { public: // The constructor is provided to avoid synthesized memsets. WinSymbolizerTool() {} @@ -133,10 +133,14 @@ void InitializeDbgHelpIfNeeded() { } } +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wframe-larger-than=" +#endif bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) { InitializeDbgHelpIfNeeded(); - // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx + // See https://docs.microsoft.com/en-us/windows/win32/debug/retrieving-symbol-information-by-address char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); @@ -162,6 +166,9 @@ bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) { // Otherwise, try llvm-symbolizer. return got_fileline; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif const char *WinSymbolizerTool::Demangle(const char *name) { CHECK(is_dbghelp_initialized); @@ -310,7 +317,7 @@ Symbolizer *Symbolizer::PlatformInit() { } void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); + Symbolizer::GetOrInit()->LateInitializeTools(); } } // namespace __sanitizer diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc index f64b403d62aa8..ba7ed46f861cc 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc @@ -13,7 +13,7 @@ // NetBSD uses libc calls directly #if !SANITIZER_NETBSD -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN # define SYSCALL(name) SYS_ ## name #else # define SYSCALL(name) __NR_ ## name diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_riscv64.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_riscv64.inc new file mode 100644 index 0000000000000..89c12602057c7 --- /dev/null +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_riscv64.inc @@ -0,0 +1,174 @@ +//===-- sanitizer_syscall_linux_riscv64.inc ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementations of internal_syscall and internal_iserror for Linux/riscv64. +// +//===----------------------------------------------------------------------===// + +// About local register variables: +// https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables +// +// Kernel ABI... +// To my surprise I haven't found much information regarding it. +// Kernel source and internet browsing shows that: +// syscall number is passed in a7 +// (http://man7.org/linux/man-pages/man2/syscall.2.html) results are return in +// a0 and a1 (http://man7.org/linux/man-pages/man2/syscall.2.html) arguments +// are passed in: a0-a7 (see below) +// +// Regarding the arguments. The only "documentation" I could find is +// this comment (!!!) by Bruce Hold on google forums (!!!): +// https://groups.google.com/a/groups.riscv.org/forum/#!topic/sw-dev/exbrzM3GZDQ +// Confirmed by inspecting glibc sources. +// Great way to document things. +#define SYSCALL(name) __NR_##name + +#define INTERNAL_SYSCALL_CLOBBERS "memory" + +static uptr __internal_syscall(u64 nr) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0"); + __asm__ volatile("ecall\n\t" + : "=r"(a0) + : "r"(a7) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall0(n) (__internal_syscall)(n) + +static uptr __internal_syscall(u64 nr, u64 arg1) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall1(n, a1) (__internal_syscall)(n, (u64)(a1)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall2(n, a1, a2) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall3(n, a1, a2, a3) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, + u64 arg4) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall4(n, a1, a2, a3, a4) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4, + long arg5) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + register u64 a4 asm("a4") = arg5; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall5(n, a1, a2, a3, a4, a5) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4, + long arg5, long arg6) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + register u64 a4 asm("a4") = arg5; + register u64 a5 asm("a5") = arg6; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5), (long)(a6)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4, + long arg5, long arg6, long arg7) { + register u64 a7 asm("a7") = nr; + register u64 a0 asm("a0") = arg1; + register u64 a1 asm("a1") = arg2; + register u64 a2 asm("a2") = arg3; + register u64 a3 asm("a3") = arg4; + register u64 a4 asm("a4") = arg5; + register u64 a5 asm("a5") = arg6; + register u64 a6 asm("a6") = arg7; + __asm__ volatile("ecall\n\t" + : "+r"(a0) + : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), + "r"(a6) + : INTERNAL_SYSCALL_CLOBBERS); + return a0; +} +#define __internal_syscall7(n, a1, a2, a3, a4, a5, a6, a7) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5), (long)(a6), (long)(a7)) + +#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n +#define __SYSCALL_NARGS(...) \ + __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, ) +#define __SYSCALL_CONCAT_X(a, b) a##b +#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b) +#define __SYSCALL_DISP(b, ...) \ + __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__) + +// Helper function used to avoid clobbering of errno. +bool internal_iserror(uptr retval, int *rverrno) { + if (retval >= (uptr)-4095) { + if (rverrno) + *rverrno = -retval; + return true; + } + return false; +} diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc index 02b7e11b1677f..c4a9d99fe2f01 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc @@ -42,8 +42,8 @@ // DO NOT EDIT! THIS FILE HAS BEEN GENERATED! // // Generated with: generate_netbsd_syscalls.awk -// Generated date: 2019-12-24 -// Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp +// Generated date: 2020-09-10 +// Generated from: syscalls.master,v 1.306 2020/08/14 00:53:16 riastradh Exp // //===----------------------------------------------------------------------===// @@ -872,7 +872,13 @@ PRE_SYSCALL(dup2)(long long from_, long long to_) { /* Nothing to do */ } POST_SYSCALL(dup2)(long long res, long long from_, long long to_) { /* Nothing to do */ } -/* syscall 91 has been skipped */ +PRE_SYSCALL(getrandom)(void *buf_, long long buflen_, long long flags_) { + /* TODO */ +} +POST_SYSCALL(getrandom) +(long long res, void *buf_, long long buflen_, long long flags_) { + /* TODO */ +} PRE_SYSCALL(fcntl)(long long fd_, long long cmd_, void *arg_) { /* Nothing to do */ } @@ -1332,9 +1338,29 @@ PRE_SYSCALL(compat_09_ouname)(void *name_) { /* TODO */ } POST_SYSCALL(compat_09_ouname)(long long res, void *name_) { /* TODO */ } PRE_SYSCALL(sysarch)(long long op_, void *parms_) { /* TODO */ } POST_SYSCALL(sysarch)(long long res, long long op_, void *parms_) { /* TODO */ } -/* syscall 166 has been skipped */ -/* syscall 167 has been skipped */ -/* syscall 168 has been skipped */ +PRE_SYSCALL(__futex) +(void *uaddr_, long long op_, long long val_, void *timeout_, void *uaddr2_, + long long val2_, long long val3_) { + /* TODO */ +} +POST_SYSCALL(__futex) +(long long res, void *uaddr_, long long op_, long long val_, void *timeout_, + void *uaddr2_, long long val2_, long long val3_) { + /* TODO */ +} +PRE_SYSCALL(__futex_set_robust_list)(void *head_, long long len_) { /* TODO */ } +POST_SYSCALL(__futex_set_robust_list) +(long long res, void *head_, long long len_) { + /* TODO */ +} +PRE_SYSCALL(__futex_get_robust_list) +(long long lwpid_, void **headp_, void *lenp_) { + /* TODO */ +} +POST_SYSCALL(__futex_get_robust_list) +(long long res, long long lwpid_, void **headp_, void *lenp_) { + /* TODO */ +} #if !defined(_LP64) PRE_SYSCALL(compat_10_osemsys) (long long which_, long long a2_, long long a3_, long long a4_, long long a5_) { @@ -3824,6 +3850,87 @@ PRE_SYSCALL(__fhstatvfs190) } POST_SYSCALL(__fhstatvfs190) (long long res, void *fhp_, long long fh_size_, void *buf_, long long flags_) {} +PRE_SYSCALL(__acl_get_link)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_get_link) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_set_link)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_set_link) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_delete_link)(void *path_, long long type_) { /* TODO */ } +POST_SYSCALL(__acl_delete_link)(long long res, void *path_, long long type_) { + /* TODO */ +} +PRE_SYSCALL(__acl_aclcheck_link)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_aclcheck_link) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_get_file)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_get_file) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_set_file)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_set_file) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_get_fd)(long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_get_fd) +(long long res, long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_set_fd)(long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_set_fd) +(long long res, long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_delete_file)(void *path_, long long type_) { /* TODO */ } +POST_SYSCALL(__acl_delete_file)(long long res, void *path_, long long type_) { + /* TODO */ +} +PRE_SYSCALL(__acl_delete_fd)(long long filedes_, long long type_) { /* TODO */ } +POST_SYSCALL(__acl_delete_fd) +(long long res, long long filedes_, long long type_) { + /* TODO */ +} +PRE_SYSCALL(__acl_aclcheck_file)(void *path_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_aclcheck_file) +(long long res, void *path_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(__acl_aclcheck_fd) +(long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +POST_SYSCALL(__acl_aclcheck_fd) +(long long res, long long filedes_, long long type_, void *aclp_) { + /* TODO */ +} +PRE_SYSCALL(lpathconf)(void *path_, long long name_) { /* TODO */ } +POST_SYSCALL(lpathconf)(long long res, void *path_, long long name_) { + /* TODO */ +} #undef SYS_MAXSYSARGS } // extern "C" diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h index 493aa988f7e6d..85c522a31cac4 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h @@ -39,8 +39,6 @@ enum class ThreadType { class ThreadContextBase { public: explicit ThreadContextBase(u32 tid); - ~ThreadContextBase(); // Should never be called. - const u32 tid; // Thread ID. Main thread should have tid = 0. u64 unique_id; // Unique thread ID. u32 reuse_count; // Number of times this tid was reused. @@ -80,6 +78,9 @@ class ThreadContextBase { virtual void OnCreated(void *arg) {} virtual void OnReset() {} virtual void OnDetached(void *arg) {} + + protected: + ~ThreadContextBase(); }; typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp index 9ca898a306a88..1f664b6cf5b8f 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp @@ -12,6 +12,7 @@ #include "sanitizer_tls_get_addr.h" +#include "sanitizer_atomic.h" #include "sanitizer_flags.h" #include "sanitizer_platform_interceptors.h" @@ -42,46 +43,66 @@ static atomic_uintptr_t number_of_live_dtls; static const uptr kDestroyedThread = -1; -static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) { - if (!size) return; - VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size); - UnmapOrDie(dtv, size * sizeof(DTLS::DTV)); +static void DTLS_Deallocate(DTLS::DTVBlock *block) { + VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", block); + UnmapOrDie(block, sizeof(DTLS::DTVBlock)); atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed); } -static inline void DTLS_Resize(uptr new_size) { - if (dtls.dtv_size >= new_size) return; - new_size = RoundUpToPowerOfTwo(new_size); - new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV)); - DTLS::DTV *new_dtv = - (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize"); +static DTLS::DTVBlock *DTLS_NextBlock(atomic_uintptr_t *cur) { + uptr v = atomic_load(cur, memory_order_acquire); + if (v == kDestroyedThread) + return nullptr; + DTLS::DTVBlock *next = (DTLS::DTVBlock *)v; + if (next) + return next; + DTLS::DTVBlock *new_dtv = + (DTLS::DTVBlock *)MmapOrDie(sizeof(DTLS::DTVBlock), "DTLS_NextBlock"); + uptr prev = 0; + if (!atomic_compare_exchange_strong(cur, &prev, (uptr)new_dtv, + memory_order_seq_cst)) { + UnmapOrDie(new_dtv, sizeof(DTLS::DTVBlock)); + return (DTLS::DTVBlock *)prev; + } uptr num_live_dtls = atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed); - VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls); - CHECK_LT(num_live_dtls, 1 << 20); - uptr old_dtv_size = dtls.dtv_size; - DTLS::DTV *old_dtv = dtls.dtv; - if (old_dtv_size) - internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV)); - dtls.dtv = new_dtv; - dtls.dtv_size = new_size; - if (old_dtv_size) - DTLS_Deallocate(old_dtv, old_dtv_size); + VReport(2, "__tls_get_addr: DTLS_NextBlock %p %zd\n", &dtls, num_live_dtls); + return new_dtv; +} + +static DTLS::DTV *DTLS_Find(uptr id) { + VReport(2, "__tls_get_addr: DTLS_Find %p %zd\n", &dtls, id); + static constexpr uptr kPerBlock = ARRAY_SIZE(DTLS::DTVBlock::dtvs); + DTLS::DTVBlock *cur = DTLS_NextBlock(&dtls.dtv_block); + if (!cur) + return nullptr; + for (; id >= kPerBlock; id -= kPerBlock) cur = DTLS_NextBlock(&cur->next); + return cur->dtvs + id; } void DTLS_Destroy() { if (!common_flags()->intercept_tls_get_addr) return; - VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size); - uptr s = dtls.dtv_size; - dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety. - DTLS_Deallocate(dtls.dtv, s); + VReport(2, "__tls_get_addr: DTLS_Destroy %p\n", &dtls); + DTLS::DTVBlock *block = (DTLS::DTVBlock *)atomic_exchange( + &dtls.dtv_block, kDestroyedThread, memory_order_release); + while (block) { + DTLS::DTVBlock *next = + (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire); + DTLS_Deallocate(block); + block = next; + } } #if defined(__powerpc64__) || defined(__mips__) // This is glibc's TLS_DTV_OFFSET: // "Dynamic thread vector pointers point 0x8000 past the start of each -// TLS block." +// TLS block." (sysdeps//dl-tls.h) static const uptr kDtvOffset = 0x8000; +#elif defined(__riscv) +// This is glibc's TLS_DTV_OFFSET: +// "Dynamic thread vector pointers point 0x800 past the start of each +// TLS block." (sysdeps/riscv/dl-tls.h) +static const uptr kDtvOffset = 0x800; #else static const uptr kDtvOffset = 0; #endif @@ -91,9 +112,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, if (!common_flags()->intercept_tls_get_addr) return 0; TlsGetAddrParam *arg = reinterpret_cast(arg_void); uptr dso_id = arg->dso_id; - if (dtls.dtv_size == kDestroyedThread) return 0; - DTLS_Resize(dso_id + 1); - if (dtls.dtv[dso_id].beg) return 0; + DTLS::DTV *dtv = DTLS_Find(dso_id); + if (!dtv || dtv->beg) + return 0; uptr tls_size = 0; uptr tls_beg = reinterpret_cast(res) - arg->offset - kDtvOffset; VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p " @@ -121,9 +142,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, // This may happen inside the DTOR of main thread, so just ignore it. tls_size = 0; } - dtls.dtv[dso_id].beg = tls_beg; - dtls.dtv[dso_id].size = tls_size; - return dtls.dtv + dso_id; + dtv->beg = tls_beg; + dtv->size = tls_size; + return dtv; } void DTLS_on_libc_memalign(void *ptr, uptr size) { @@ -136,7 +157,8 @@ void DTLS_on_libc_memalign(void *ptr, uptr size) { DTLS *DTLS_Get() { return &dtls; } bool DTLSInDestruction(DTLS *dtls) { - return dtls->dtv_size == kDestroyedThread; + return atomic_load(&dtls->dtv_block, memory_order_relaxed) == + kDestroyedThread; } #else diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h index c7cd5a8bffcf9..a599c0bbc75cc 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h @@ -28,6 +28,7 @@ #ifndef SANITIZER_TLS_GET_ADDR_H #define SANITIZER_TLS_GET_ADDR_H +#include "sanitizer_atomic.h" #include "sanitizer_common.h" namespace __sanitizer { @@ -38,15 +39,31 @@ struct DTLS { struct DTV { uptr beg, size; }; + struct DTVBlock { + atomic_uintptr_t next; + DTV dtvs[(4096UL - sizeof(next)) / sizeof(DTLS::DTV)]; + }; + + static_assert(sizeof(DTVBlock) <= 4096UL, "Unexpected block size"); - uptr dtv_size; - DTV *dtv; // dtv_size elements, allocated by MmapOrDie. + atomic_uintptr_t dtv_block; // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp uptr last_memalign_size; uptr last_memalign_ptr; }; +template +void ForEachDVT(DTLS *dtls, const Fn &fn) { + DTLS::DTVBlock *block = + (DTLS::DTVBlock *)atomic_load(&dtls->dtv_block, memory_order_acquire); + while (block) { + int id = 0; + for (auto &d : block->dtvs) fn(d, id++); + block = (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire); + } +} + // Returns pointer and size of a linker-allocated TLS block. // Each block is returned exactly once. DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin, diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp index 8e06940685dcb..7e01c81d0422a 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp @@ -37,8 +37,16 @@ void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) { // Skip the RTL frames by searching for the PC in the stacktrace. uptr pc_location = LocatePcInTrace(pc); PopStackFrames(pc_location); + + // Replace the first frame with the PC because the frame in the + // stacktrace might be incorrect. + trace_buffer[0] = pc; } +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wframe-larger-than=" +#endif void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { CHECK(context); CHECK_GE(max_depth, 2); @@ -70,6 +78,9 @@ void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) { trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset; } } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif #endif // #if !SANITIZER_GO #endif // SANITIZER_WINDOWS diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp index 36dde49d87083..63c90785f2702 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -94,6 +94,10 @@ uptr internal_getpid() { return GetProcessId(GetCurrentProcess()); } +int internal_dlinfo(void *handle, int request, void *p) { + UNIMPLEMENTED(); +} + // In contrast to POSIX, on Windows GetCurrentThreadId() // returns a system-unique identifier. tid_t GetTid() { @@ -344,6 +348,22 @@ bool DontDumpShadowMemory(uptr addr, uptr length) { return true; } +uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, + uptr min_shadow_base_alignment, + UNUSED uptr &high_mem_end) { + const uptr granularity = GetMmapGranularity(); + const uptr alignment = + Max(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); + const uptr left_padding = + Max(granularity, 1ULL << min_shadow_base_alignment); + uptr space_size = shadow_size_bytes + left_padding; + uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, + granularity, nullptr, nullptr); + CHECK_NE((uptr)0, shadow_start); + CHECK(IsAligned(shadow_start, alignment)); + return shadow_start; +} + uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, uptr *largest_gap_found, uptr *max_occupied_addr) { @@ -471,8 +491,6 @@ void DumpProcessMap() { } #endif -void PrintModuleMap() { } - void DisableCoreDumperIfNecessary() { // Do nothing. } @@ -593,6 +611,10 @@ static uptr GetPreferredBase(const char *modname) { return (uptr)pe_header->ImageBase; } +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wframe-larger-than=" +#endif void ListOfModules::init() { clearOrInit(); HANDLE cur_process = GetCurrentProcess(); @@ -654,6 +676,9 @@ void ListOfModules::init() { } UnmapOrDie(hmodules, modules_buffer_size); } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif void ListOfModules::fallbackInit() { clear(); } @@ -787,7 +812,7 @@ uptr GetRSS() { return counters.WorkingSetSize; } -void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } +void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; } void internal_join_thread(void *th) { } // ---------------------- BlockingMutex ---------------- {{{1 @@ -938,22 +963,27 @@ void SignalContext::InitPcSpBp() { uptr SignalContext::GetAddress() const { EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; - return exception_record->ExceptionInformation[1]; + if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) + return exception_record->ExceptionInformation[1]; + return (uptr)exception_record->ExceptionAddress; } bool SignalContext::IsMemoryAccess() const { - return GetWriteFlag() != SignalContext::UNKNOWN; + return ((EXCEPTION_RECORD *)siginfo)->ExceptionCode == + EXCEPTION_ACCESS_VIOLATION; } -bool SignalContext::IsTrueFaultingAddress() const { - // FIXME: Provide real implementation for this. See Linux and Mac variants. - return IsMemoryAccess(); -} +bool SignalContext::IsTrueFaultingAddress() const { return true; } SignalContext::WriteFlag SignalContext::GetWriteFlag() const { EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; + + // The write flag is only available for access violation exceptions. + if (exception_record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) + return SignalContext::UNKNOWN; + // The contents of this array are documented at - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx + // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record // The first element indicates read as 0, write as 1, or execute as 8. The // second element is the faulting address. switch (exception_record->ExceptionInformation[0]) { @@ -1060,7 +1090,8 @@ char **GetEnviron() { } pid_t StartSubprocess(const char *program, const char *const argv[], - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, + fd_t stderr_fd) { // FIXME: implement on this platform // Should be implemented based on // SymbolizerProcess::StarAtSymbolizerSubprocess @@ -1119,6 +1150,8 @@ void LogFullErrorReport(const char *buffer) { } #endif // SANITIZER_WIN_TRACE +void InitializePlatformCommonFlags(CommonFlags *cf) {} + } // namespace __sanitizer #endif // _WIN32 diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_checks.inc b/system/lib/compiler-rt/lib/ubsan/ubsan_checks.inc index 7e7216c5b4ab7..4e0c2bcf0e65f 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_checks.inc +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_checks.inc @@ -18,6 +18,8 @@ UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined") UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null") +UBSAN_CHECK(NullPointerUseWithNullability, "null-pointer-use", + "nullability-assign") UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow") UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment") UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment") @@ -30,6 +32,7 @@ UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero", "integer-divide-by-zero") UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero", "float-divide-by-zero") UBSAN_CHECK(InvalidBuiltin, "invalid-builtin-use", "invalid-builtin-use") +UBSAN_CHECK(InvalidObjCCast, "invalid-objc-cast", "invalid-objc-cast") UBSAN_CHECK(ImplicitUnsignedIntegerTruncation, "implicit-unsigned-integer-truncation", "implicit-unsigned-integer-truncation") @@ -54,6 +57,10 @@ UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "enum") UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch", "function") UBSAN_CHECK(InvalidNullReturn, "invalid-null-return", "returns-nonnull-attribute") +UBSAN_CHECK(InvalidNullReturnWithNullability, "invalid-null-return", + "nullability-return") UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument", "nonnull-attribute") +UBSAN_CHECK(InvalidNullArgumentWithNullability, "invalid-null-argument", + "nullability-arg") UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr") UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi") diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_diag.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_diag.cpp index 529cc6985763b..c8f7960db42ac 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_diag.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_diag.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_diag.cc -----------------------------------------------------===// +//===-- ubsan_diag.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp index c22fd17499725..300179adae28c 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_diag_standalone.cc ------------------------------------------===// +//===-- ubsan_diag_standalone.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp index 210b831507d2e..48bb217d45695 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_flags.cc ----------------------------------------------------===// +//===-- ubsan_flags.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -26,10 +26,6 @@ extern "C" void emscripten_builtin_free(void *); namespace __ubsan { -const char *MaybeCallUbsanDefaultOptions() { - return (&__ubsan_default_options) ? __ubsan_default_options() : ""; -} - static const char *GetFlag(const char *flag) { // We cannot call getenv() from inside a preinit array initializer if (SANITIZER_CAN_USE_PREINIT_ARRAY) { @@ -76,8 +72,7 @@ void InitializeFlags() { RegisterUbsanFlags(&parser, f); // Override from user-specified string. - parser.ParseString(MaybeCallUbsanDefaultOptions()); - + parser.ParseString(__ubsan_default_options()); // Override from environment variable. #if SANITIZER_EMSCRIPTEN char *options = (char*) EM_ASM_INT({ @@ -88,7 +83,7 @@ void InitializeFlags() { parser.ParseString(options); emscripten_builtin_free(options); #else - parser.ParseString(GetEnv("UBSAN_OPTIONS")); + parser.ParseStringFromEnv("UBSAN_OPTIONS"); #endif // SANITIZER_EMSCRIPTEN InitializeCommonFlags(); diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.h b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.h index daa0d7c701e04..c47009bafe539 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.h +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.h @@ -34,8 +34,6 @@ inline Flags *flags() { return &ubsan_flags; } void InitializeFlags(); void RegisterUbsanFlags(FlagParser *parser, Flags *f); -const char *MaybeCallUbsanDefaultOptions(); - } // namespace __ubsan extern "C" { diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.cpp index 938ac89750f36..b070a378c0d47 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_handlers.cc -------------------------------------------------===// +//===-- ubsan_handlers.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -16,6 +16,7 @@ #include "ubsan_diag.h" #include "ubsan_flags.h" #include "ubsan_monitor.h" +#include "ubsan_value.h" #include "sanitizer_common/sanitizer_common.h" @@ -36,6 +37,45 @@ bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) { return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename()); } +/// Situations in which we might emit a check for the suitability of a +/// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in +/// clang. +enum TypeCheckKind { + /// Checking the operand of a load. Must be suitably sized and aligned. + TCK_Load, + /// Checking the destination of a store. Must be suitably sized and aligned. + TCK_Store, + /// Checking the bound value in a reference binding. Must be suitably sized + /// and aligned, but is not required to refer to an object (until the + /// reference is used), per core issue 453. + TCK_ReferenceBinding, + /// Checking the object expression in a non-static data member access. Must + /// be an object within its lifetime. + TCK_MemberAccess, + /// Checking the 'this' pointer for a call to a non-static member function. + /// Must be an object within its lifetime. + TCK_MemberCall, + /// Checking the 'this' pointer for a constructor call. + TCK_ConstructorCall, + /// Checking the operand of a static_cast to a derived pointer type. Must be + /// null or an object within its lifetime. + TCK_DowncastPointer, + /// Checking the operand of a static_cast to a derived reference type. Must + /// be an object within its lifetime. + TCK_DowncastReference, + /// Checking the operand of a cast to a base object. Must be suitably sized + /// and aligned. + TCK_Upcast, + /// Checking the operand of a cast to a virtual base object. Must be an + /// object within its lifetime. + TCK_UpcastToVirtualBase, + /// Checking the value assigned to a _Nonnull pointer. Must not be null. + TCK_NonnullAssign, + /// Checking the operand of a dynamic_cast or a typeid expression. Must be + /// null or an object within its lifetime. + TCK_DynamicOperation +}; + const char *TypeCheckKinds[] = { "load of", "store to", "reference binding to", "member access within", "member call on", "constructor call on", "downcast of", "downcast of", @@ -50,7 +90,9 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, uptr Alignment = (uptr)1 << Data->LogAlignment; ErrorType ET; if (!Pointer) - ET = ErrorType::NullPointerUse; + ET = (Data->TypeCheckKind == TCK_NonnullAssign) + ? ErrorType::NullPointerUseWithNullability + : ErrorType::NullPointerUse; else if (Pointer & (Alignment - 1)) ET = ErrorType::MisalignedPointerUse; else @@ -71,6 +113,7 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, switch (ET) { case ErrorType::NullPointerUse: + case ErrorType::NullPointerUseWithNullability: Diag(Loc, DL_Error, ET, "%0 null pointer of type %1") << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; break; @@ -598,13 +641,44 @@ void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) { Die(); } +static void handleInvalidObjCCast(InvalidObjCCast *Data, ValueHandle Pointer, + ReportOptions Opts) { + SourceLocation Loc = Data->Loc.acquire(); + ErrorType ET = ErrorType::InvalidObjCCast; + + if (ignoreReport(Loc, Opts, ET)) + return; + + ScopedReport R(Opts, Loc, ET); + + const char *GivenClass = getObjCClassName(Pointer); + const char *GivenClassStr = GivenClass ? GivenClass : ""; + + Diag(Loc, DL_Error, ET, + "invalid ObjC cast, object is a '%0', but expected a %1") + << GivenClassStr << Data->ExpectedType; +} + +void __ubsan::__ubsan_handle_invalid_objc_cast(InvalidObjCCast *Data, + ValueHandle Pointer) { + GET_REPORT_OPTIONS(false); + handleInvalidObjCCast(Data, Pointer, Opts); +} +void __ubsan::__ubsan_handle_invalid_objc_cast_abort(InvalidObjCCast *Data, + ValueHandle Pointer) { + GET_REPORT_OPTIONS(true); + handleInvalidObjCCast(Data, Pointer, Opts); + Die(); +} + static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr, ReportOptions Opts, bool IsAttr) { if (!LocPtr) UNREACHABLE("source location pointer is null!"); SourceLocation Loc = LocPtr->acquire(); - ErrorType ET = ErrorType::InvalidNullReturn; + ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn + : ErrorType::InvalidNullReturnWithNullability; if (ignoreReport(Loc, Opts, ET)) return; @@ -648,7 +722,8 @@ void __ubsan::__ubsan_handle_nullability_return_v1_abort( static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts, bool IsAttr) { SourceLocation Loc = Data->Loc.acquire(); - ErrorType ET = ErrorType::InvalidNullArgument; + ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument + : ErrorType::InvalidNullArgumentWithNullability; if (ignoreReport(Loc, Opts, ET)) return; diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.h b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.h index 22ca96422381c..219fb15de55fe 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.h +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.h @@ -168,6 +168,14 @@ struct InvalidBuiltinData { /// Handle a builtin called in an invalid way. RECOVERABLE(invalid_builtin, InvalidBuiltinData *Data) +struct InvalidObjCCast { + SourceLocation Loc; + const TypeDescriptor &ExpectedType; +}; + +/// Handle an invalid ObjC cast. +RECOVERABLE(invalid_objc_cast, InvalidObjCCast *Data, ValueHandle Pointer) + struct NonNullReturnData { SourceLocation AttrLoc; }; diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp index 9c324cc19a11f..2a6d558de0342 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_handlers_cxx.cc ---------------------------------------------===// +//===-- ubsan_handlers_cxx.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_init.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_init.cpp index f0bbe1ef10768..e0be5a72ec42f 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_init.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_init.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_init.cc -----------------------------------------------------===// +//===-- ubsan_init.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -37,10 +37,12 @@ static void CommonStandaloneInit() { SanitizerToolName = GetSanititizerToolName(); CacheBinaryName(); InitializeFlags(); + __sanitizer::InitializePlatformEarly(); __sanitizer_set_report_path(common_flags()->log_path); AndroidLogInit(); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); CommonInit(); + Symbolizer::LateInitialize(); } void __ubsan::InitAsStandalone() { diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp index 323c2c1f9a474..91c3f57b424b9 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_init_standalone.cc ------------------------------------------===// +//===-- ubsan_init_standalone.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp index bf344a2a9fcdb..fabbf919a4022 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_init_standalone_preinit.cc ---------------------------------===// +//===-- ubsan_init_standalone_preinit.cpp --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_interface.inc b/system/lib/compiler-rt/lib/ubsan/ubsan_interface.inc index 1e44bc2171ded..94337d85017b4 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_interface.inc +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_interface.inc @@ -27,6 +27,8 @@ INTERFACE_FUNCTION(__ubsan_handle_implicit_conversion) INTERFACE_FUNCTION(__ubsan_handle_implicit_conversion_abort) INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin) INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin_abort) +INTERFACE_FUNCTION(__ubsan_handle_invalid_objc_cast) +INTERFACE_FUNCTION(__ubsan_handle_invalid_objc_cast_abort) INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value) INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value_abort) INTERFACE_FUNCTION(__ubsan_handle_missing_return) diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_monitor.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_monitor.cpp index cb97a8ff1b887..d064e95f76f72 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_monitor.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_monitor.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_monitor.cc ----------------------------------------*- C++ -*-===// +//===-- ubsan_monitor.cpp ---------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_platform.h b/system/lib/compiler-rt/lib/ubsan/ubsan_platform.h index 684af5a5c179b..82efd0c3414ee 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_platform.h +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_platform.h @@ -14,7 +14,7 @@ // Other platforms should be easy to add, and probably work as-is. #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ - defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ (defined(__sun__) && defined(__svr4__)) || \ defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__) || \ defined(__EMSCRIPTEN__) diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp index 5f8a8c0662d4f..8d980e1a26391 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp @@ -1,5 +1,4 @@ -//=-- ubsan_signals_standalone.cc -//------------------------------------------------===// +//=-- ubsan_signals_standalone.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash.cpp index 431495672b55a..8f4b9aee50bbd 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_type_hash.cc ------------------------------------------------===// +//===-- ubsan_type_hash.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -11,7 +11,7 @@ // permitted to use language features which require a C++ ABI library. // // Most of the implementation lives in an ABI-specific source file -// (ubsan_type_hash_{itanium,win}.cc). +// (ubsan_type_hash_{itanium,win}.cpp). // //===----------------------------------------------------------------------===// diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp index c4b048f20a8c9..d82b542a020e7 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_type_hash_itanium.cc ----------------------------------------===// +//===-- ubsan_type_hash_itanium.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -12,10 +12,11 @@ #include "sanitizer_common/sanitizer_platform.h" #include "ubsan_platform.h" -#if CAN_SANITIZE_UB && !SANITIZER_WINDOWS +#if CAN_SANITIZE_UB && !defined(_MSC_VER) #include "ubsan_type_hash.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_ptrauth.h" // The following are intended to be binary compatible with the definitions // given in the Itanium ABI. We make no attempt to be ODR-compatible with @@ -194,6 +195,7 @@ struct VtablePrefix { std::type_info *TypeInfo; }; VtablePrefix *getVtablePrefix(void *Vtable) { + Vtable = ptrauth_auth_data(Vtable, ptrauth_key_cxx_vtable_pointer, 0); VtablePrefix *Vptr = reinterpret_cast(Vtable); VtablePrefix *Prefix = Vptr - 1; if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix))) diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp index c7b2e45af4e66..106fa1b85a558 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_type_hash_win.cc --------------------------------------------===// +//===-- ubsan_type_hash_win.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -12,7 +12,7 @@ #include "sanitizer_common/sanitizer_platform.h" #include "ubsan_platform.h" -#if CAN_SANITIZE_UB && SANITIZER_WINDOWS +#if CAN_SANITIZE_UB && defined(_MSC_VER) #include "ubsan_type_hash.h" #include "sanitizer_common/sanitizer_common.h" diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_value.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_value.cpp index ba336a6673ca7..79c3ba991d398 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_value.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_value.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_value.cc ----------------------------------------------------===// +//===-- ubsan_value.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -16,9 +16,57 @@ #include "ubsan_value.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_mutex.h" + +// TODO(dliew): Prefer '__APPLE__' here over 'SANITIZER_MAC', as the latter is +// unclear. rdar://58124919 tracks using a more obviously portable guard. +#if defined(__APPLE__) +#include +#endif using namespace __ubsan; +typedef const char *(*ObjCGetClassNameTy)(void *); + +const char *__ubsan::getObjCClassName(ValueHandle Pointer) { +#if defined(__APPLE__) + // We need to query the ObjC runtime for some information, but do not want + // to introduce a static dependency from the ubsan runtime onto ObjC. Try to + // grab a handle to the ObjC runtime used by the process. + static bool AttemptedDlopen = false; + static void *ObjCHandle = nullptr; + static void *ObjCObjectGetClassName = nullptr; + + // Prevent threads from racing to dlopen(). + static __sanitizer::StaticSpinMutex Lock; + { + __sanitizer::SpinMutexLock Guard(&Lock); + + if (!AttemptedDlopen) { + ObjCHandle = dlopen( + "/usr/lib/libobjc.A.dylib", + RTLD_LAZY // Only bind symbols when used. + | RTLD_LOCAL // Only make symbols available via the handle. + | RTLD_NOLOAD // Do not load the dylib, just grab a handle if the + // image is already loaded. + | RTLD_FIRST // Only search the image pointed-to by the handle. + ); + AttemptedDlopen = true; + if (!ObjCHandle) + return nullptr; + ObjCObjectGetClassName = dlsym(ObjCHandle, "object_getClassName"); + } + } + + if (!ObjCObjectGetClassName) + return nullptr; + + return ObjCGetClassNameTy(ObjCObjectGetClassName)((void *)Pointer); +#else + return nullptr; +#endif +} + SIntMax Value::getSIntValue() const { CHECK(getType().isSignedIntegerTy()); if (isInlineInt()) { diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_value.h b/system/lib/compiler-rt/lib/ubsan/ubsan_value.h index a216e3a147e91..e0957276dd241 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_value.h +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_value.h @@ -135,6 +135,9 @@ class TypeDescriptor { /// \brief An opaque handle to a value. typedef uptr ValueHandle; +/// Returns the class name of the given ObjC object, or null if the name +/// cannot be found. +const char *getObjCClassName(ValueHandle Pointer); /// \brief Representation of an operand value provided by the instrumented code. /// diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp index fd39e210af0a8..5ac7fc3e08e4c 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_win_dll_thunk.cc --------------------------------------------===// +//===-- ubsan_win_dll_thunk.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp index 87ada6131cde0..00722b4033a53 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_win_dynamic_runtime_thunk.cc --------------------------------===// +//===-- ubsan_win_dynamic_runtime_thunk.cpp -------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp index 8cf6344ce1d80..01db0c0ce78ab 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_win_weak_interception.cc ------------------------------------===// +//===-- ubsan_win_weak_interception.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp b/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp index ed62ddd0fa348..6a1903da62ce7 100644 --- a/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp +++ b/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp @@ -10,7 +10,7 @@ extern "C" void ubsan_message(const char *msg); static void message(const char *msg) { ubsan_message(msg); } #else static void message(const char *msg) { - write(2, msg, strlen(msg)); + (void)write(2, msg, strlen(msg)); } #endif @@ -109,6 +109,7 @@ HANDLER(vla_bound_not_positive, "vla-bound-not-positive") HANDLER(float_cast_overflow, "float-cast-overflow") HANDLER(load_invalid_value, "load-invalid-value") HANDLER(invalid_builtin, "invalid-builtin") +HANDLER(invalid_objc_cast, "invalid-objc-cast") HANDLER(function_type_mismatch, "function-type-mismatch") HANDLER(implicit_conversion, "implicit-conversion") HANDLER(nonnull_arg, "nonnull-arg") diff --git a/system/lib/compiler-rt/readme.txt b/system/lib/compiler-rt/readme.txt index 7d2e23e59d57f..ea377d0dc9a0f 100644 --- a/system/lib/compiler-rt/readme.txt +++ b/system/lib/compiler-rt/readme.txt @@ -1,7 +1,7 @@ llvm's compiler-rt ------------------ -These files are from the llvm-project based on release 10.0.0. +These files are from the llvm-project based on release 12.0.0. We maintain a local fork of llvm-project that contains any emscripten specific patches: @@ -10,8 +10,8 @@ specific patches: The current patch is based on: -tag: llvmorg-10.0.0 -git: d32170dbd5b0d54436537b6b75beaf44324e0c28 +tag: llvmorg-12.0.0 +git: d28af7c654d8db0b68c175db5ce212d74fb5e9bc Update Instructions ------------------- @@ -23,4 +23,4 @@ Modifications For a list of changes from upstream see the compiler-rt files that are part of: -https://github.com/llvm/llvm-project/compare/llvmorg-10.0.0...emscripten-core:emscripten-libs-10.0.0 +https://github.com/llvm/llvm-project/compare/llvmorg-12.0.0...emscripten-core:emscripten-libs-12.0.0 diff --git a/system/lib/pthread/library_pthread_stub.c b/system/lib/pthread/library_pthread_stub.c index 38ac19d075be2..bca3408a5a846 100644 --- a/system/lib/pthread/library_pthread_stub.c +++ b/system/lib/pthread/library_pthread_stub.c @@ -188,10 +188,13 @@ _Noreturn void pthread_exit(void* status) { exit((int)status); } -int pthread_detach(pthread_t t) { +int emscripten_builtin_pthread_detach(pthread_t t) { return 0; } +weak_alias(emscripten_builtin_pthread_detach, pthread_detach); +weak_alias(emscripten_builtin_pthread_detach, thrd_detach); + pthread_t emscripten_main_browser_thread_id() { return __pthread_self(); }