mirror of
https://github.com/opnsense/src.git
synced 2026-06-11 09:41:03 -04:00
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
the upstream release_80 branch r355313 (effectively, 8.0.0 rc3). The release will follow very soon, but no more functional changes are expected. Release notes for llvm, clang and lld 8.0.0 will soon be available here: <https://releases.llvm.org/8.0.0/docs/ReleaseNotes.html> <https://releases.llvm.org/8.0.0/tools/clang/docs/ReleaseNotes.html> <https://releases.llvm.org/8.0.0/tools/lld/docs/ReleaseNotes.html> PR: 236062 Relnotes: yes MFC after: 1 month
This commit is contained in:
commit
dfcb9f2c4b
4798 changed files with 320568 additions and 183848 deletions
|
|
@ -38,6 +38,158 @@
|
|||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20190304: new libc++ import which bumps version from 7.0.1 to 8.0.0.
|
||||
OLD_FILES+=usr/include/c++/v1/experimental/dynarray
|
||||
# 20190304: new clang import which bumps version from 7.0.1 to 8.0.0.
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/allocator_interface.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/asan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/common_interface_defs.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/coverage_interface.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/dfsan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/esan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/hwasan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/linux_syscall_hooks.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/lsan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/msan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/netbsd_syscall_hooks.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/scudo_interface.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/tsan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/tsan_interface_atomic.h
|
||||
OLD_DIRS+=usr/lib/clang/7.0.1/include/sanitizer
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_builtin_vars.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_cmath.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_complex_builtins.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_device_functions.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_intrinsics.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_libdevice_declares.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_math_forward_declares.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_runtime_wrapper.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__stddef_max_align_t.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__wmmintrin_aes.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/__wmmintrin_pclmul.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/adxintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/altivec.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/ammintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/arm64intr.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/arm_acle.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/arm_fp16.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/arm_neon.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/armintr.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx2intrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512bitalgintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512bwintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512cdintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512dqintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512erintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512fintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512ifmaintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512ifmavlintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512pfintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vbmi2intrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vbmiintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vbmivlintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlbitalgintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlbwintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlcdintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vldqintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlvbmi2intrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlvnniintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vnniintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vpopcntdqintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vpopcntdqvlintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/avxintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/bmi2intrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/bmiintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/cetintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/cldemoteintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/clflushoptintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/clwbintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/clzerointrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/cpuid.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/emmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/f16cintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/fma4intrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/fmaintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/fxsrintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/gfniintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/htmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/htmxlintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/ia32intrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/immintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/invpcidintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/lwpintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/lzcntintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/mm3dnow.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/mm_malloc.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/mmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/module.modulemap
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/movdirintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/msa.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/mwaitxintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/nmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/opencl-c.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/pconfigintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/pkuintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/pmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/popcntintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/prfchwintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/ptwriteintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/rdseedintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/rtmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/s390intrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/sgxintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/shaintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/smmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/tbmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/tmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/vadefs.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/vaesintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/vecintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/vpclmulqdqintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/waitpkgintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/wbnoinvdintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/wmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/x86intrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/xmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/xopintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/xsavecintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/xsaveintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/xsaveoptintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/xsavesintrin.h
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/include/xtestintrin.h
|
||||
OLD_DIRS+=usr/lib/clang/7.0.1/include
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-i386.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-i386.so
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-x86_64.so
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.msan-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-arm.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-i386.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.safestack-i386.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats-i386.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats_client-i386.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
|
||||
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
|
||||
OLD_DIRS+=usr/lib/clang/7.0.1/lib/freebsd
|
||||
OLD_DIRS+=usr/lib/clang/7.0.1/lib
|
||||
OLD_DIRS+=usr/lib/clang/7.0.1
|
||||
# 20190227: rename seq.h to seqc.h
|
||||
OLD_FILES+=usr/include/sys/seq.h
|
||||
# 20190222: libifconfig made INTERNALLIB
|
||||
|
|
|
|||
6
UPDATING
6
UPDATING
|
|
@ -31,6 +31,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
|
|||
disable the most expensive debugging functionality run
|
||||
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
|
||||
|
||||
20190304:
|
||||
Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to
|
||||
8.0.0. Please see the 20141231 entry below for information about
|
||||
prerequisites and upgrading, if you are not already using clang 3.5.0
|
||||
or higher.
|
||||
|
||||
20190219:
|
||||
drm and drm2 have been removed from the tree. Please see
|
||||
https://wiki.freebsd.org/Graphics for the latest information on
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ Full text of the relevant licenses is included below.
|
|||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2009-2018 by the contributors listed in CREDITS.TXT
|
||||
Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ extern "C" {
|
|||
Currently available with ASan only.
|
||||
*/
|
||||
void __sanitizer_purge_allocator(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -124,6 +124,12 @@ extern "C" {
|
|||
|
||||
// Symbolizes the supplied 'pc' using the format string 'fmt'.
|
||||
// Outputs at most 'out_buf_size' bytes into 'out_buf'.
|
||||
// If 'out_buf' is not empty then output is zero or more non empty C strings
|
||||
// followed by single empty C string. Multiple strings can be returned if PC
|
||||
// corresponds to inlined function. Inlined frames are printed in the order
|
||||
// from "most-inlined" to the "least-inlined", so the last frame should be the
|
||||
// not inlined function.
|
||||
// Inlined frames can be removed with 'symbolize_inline_frames=0'.
|
||||
// The format syntax is described in
|
||||
// lib/sanitizer_common/sanitizer_stacktrace_printer.h.
|
||||
void __sanitizer_symbolize_pc(void *pc, const char *fmt, char *out_buf,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,12 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// Initialize shadow but not the rest of the runtime.
|
||||
// Does not call libc unless there is an error.
|
||||
// Can be called multiple times, or not at all (in which case shadow will
|
||||
// be initialized in compiler-inserted __hwasan_init() call).
|
||||
void __hwasan_shadow_init(void);
|
||||
|
||||
// This function may be optionally provided by user and should return
|
||||
// a string containing HWASan runtime options. See asan_flags.h for details.
|
||||
const char* __hwasan_default_options(void);
|
||||
|
|
@ -26,6 +32,51 @@ extern "C" {
|
|||
void __hwasan_enable_allocator_tagging(void);
|
||||
void __hwasan_disable_allocator_tagging(void);
|
||||
|
||||
// Mark region of memory with the given tag. Both address and size need to be
|
||||
// 16-byte aligned.
|
||||
void __hwasan_tag_memory(const volatile void *p, unsigned char tag,
|
||||
size_t size);
|
||||
|
||||
/// Set pointer tag. Previous tag is lost.
|
||||
void *__hwasan_tag_pointer(const volatile void *p, unsigned char tag);
|
||||
|
||||
// Set memory tag from the current SP address to the given address to zero.
|
||||
// This is meant to annotate longjmp and other non-local jumps.
|
||||
// This function needs to know the (almost) exact destination frame address;
|
||||
// clearing shadow for the entire thread stack like __asan_handle_no_return
|
||||
// does would cause false reports.
|
||||
void __hwasan_handle_longjmp(const void *sp_dst);
|
||||
|
||||
// Libc hook for thread creation. Should be called in the child thread before
|
||||
// any instrumented code.
|
||||
void __hwasan_thread_enter();
|
||||
|
||||
// Libc hook for thread destruction. No instrumented code should run after
|
||||
// this call.
|
||||
void __hwasan_thread_exit();
|
||||
|
||||
// Print shadow and origin for the memory range to stderr in a human-readable
|
||||
// format.
|
||||
void __hwasan_print_shadow(const volatile void *x, size_t size);
|
||||
|
||||
// Print one-line report about the memory usage of the current process.
|
||||
void __hwasan_print_memory_usage();
|
||||
|
||||
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);
|
||||
void * __sanitizer___libc_memalign(size_t alignment, size_t size);
|
||||
void * __sanitizer_valloc(size_t size);
|
||||
void * __sanitizer_pvalloc(size_t size);
|
||||
void __sanitizer_free(void *ptr);
|
||||
void __sanitizer_cfree(void *ptr);
|
||||
size_t __sanitizer_malloc_usable_size(const void *ptr);
|
||||
struct mallinfo __sanitizer_mallinfo();
|
||||
int __sanitizer_mallopt(int cmd, int value);
|
||||
void __sanitizer_malloc_stats(void);
|
||||
void * __sanitizer_calloc(size_t nmemb, size_t size);
|
||||
void * __sanitizer_realloc(void *ptr, size_t size);
|
||||
void * __sanitizer_malloc(size_t size);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
|
||||
//
|
||||
// Generated with: generate_netbsd_syscalls.awk
|
||||
// Generated date: 2018-03-03
|
||||
// Generated from: syscalls.master,v 1.291 2018/01/06 16:41:23 kamil Exp
|
||||
// Generated date: 2018-10-30
|
||||
// Generated from: syscalls.master,v 1.293 2018/07/31 13:00:13 rjs Exp
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H
|
||||
|
|
@ -986,7 +986,15 @@
|
|||
#define __sanitizer_syscall_post_fpathconf(res, fd, name) \
|
||||
__sanitizer_syscall_post_impl_fpathconf(res, (long long)(fd), \
|
||||
(long long)(name))
|
||||
/* syscall 193 has been skipped */
|
||||
#define __sanitizer_syscall_pre_getsockopt2(s, level, name, val, avalsize) \
|
||||
__sanitizer_syscall_pre_impl_getsockopt2( \
|
||||
(long long)(s), (long long)(level), (long long)(name), (long long)(val), \
|
||||
(long long)(avalsize))
|
||||
#define __sanitizer_syscall_post_getsockopt2(res, s, level, name, val, \
|
||||
avalsize) \
|
||||
__sanitizer_syscall_post_impl_getsockopt2( \
|
||||
res, (long long)(s), (long long)(level), (long long)(name), \
|
||||
(long long)(val), (long long)(avalsize))
|
||||
#define __sanitizer_syscall_pre_getrlimit(which, rlp) \
|
||||
__sanitizer_syscall_pre_impl_getrlimit((long long)(which), (long long)(rlp))
|
||||
#define __sanitizer_syscall_post_getrlimit(res, which, rlp) \
|
||||
|
|
@ -1752,18 +1760,8 @@
|
|||
__sanitizer_syscall_post_impl___sigaction_sigtramp( \
|
||||
res, (long long)(signum), (long long)(nsa), (long long)(osa), \
|
||||
(long long)(tramp), (long long)(vers))
|
||||
#define __sanitizer_syscall_pre_pmc_get_info(ctr, op, args) \
|
||||
__sanitizer_syscall_pre_impl_pmc_get_info((long long)(ctr), (long long)(op), \
|
||||
(long long)(args))
|
||||
#define __sanitizer_syscall_post_pmc_get_info(res, ctr, op, args) \
|
||||
__sanitizer_syscall_post_impl_pmc_get_info( \
|
||||
res, (long long)(ctr), (long long)(op), (long long)(args))
|
||||
#define __sanitizer_syscall_pre_pmc_control(ctr, op, args) \
|
||||
__sanitizer_syscall_pre_impl_pmc_control((long long)(ctr), (long long)(op), \
|
||||
(long long)(args))
|
||||
#define __sanitizer_syscall_post_pmc_control(res, ctr, op, args) \
|
||||
__sanitizer_syscall_post_impl_pmc_control( \
|
||||
res, (long long)(ctr), (long long)(op), (long long)(args))
|
||||
/* syscall 341 has been skipped */
|
||||
/* syscall 342 has been skipped */
|
||||
#define __sanitizer_syscall_pre_rasctl(addr, len, op) \
|
||||
__sanitizer_syscall_pre_impl_rasctl((long long)(addr), (long long)(len), \
|
||||
(long long)(op))
|
||||
|
|
@ -3444,7 +3442,13 @@ void __sanitizer_syscall_post_impl_pathconf(long long res, long long path,
|
|||
void __sanitizer_syscall_pre_impl_fpathconf(long long fd, long long name);
|
||||
void __sanitizer_syscall_post_impl_fpathconf(long long res, long long fd,
|
||||
long long name);
|
||||
/* syscall 193 has been skipped */
|
||||
void __sanitizer_syscall_pre_impl_getsockopt2(long long s, long long level,
|
||||
long long name, long long val,
|
||||
long long avalsize);
|
||||
void __sanitizer_syscall_post_impl_getsockopt2(long long res, long long s,
|
||||
long long level, long long name,
|
||||
long long val,
|
||||
long long avalsize);
|
||||
void __sanitizer_syscall_pre_impl_getrlimit(long long which, long long rlp);
|
||||
void __sanitizer_syscall_post_impl_getrlimit(long long res, long long which,
|
||||
long long rlp);
|
||||
|
|
@ -4001,14 +4005,8 @@ void __sanitizer_syscall_pre_impl___sigaction_sigtramp(long long signum,
|
|||
void __sanitizer_syscall_post_impl___sigaction_sigtramp(
|
||||
long long res, long long signum, long long nsa, long long osa,
|
||||
long long tramp, long long vers);
|
||||
void __sanitizer_syscall_pre_impl_pmc_get_info(long long ctr, long long op,
|
||||
long long args);
|
||||
void __sanitizer_syscall_post_impl_pmc_get_info(long long res, long long ctr,
|
||||
long long op, long long args);
|
||||
void __sanitizer_syscall_pre_impl_pmc_control(long long ctr, long long op,
|
||||
long long args);
|
||||
void __sanitizer_syscall_post_impl_pmc_control(long long res, long long ctr,
|
||||
long long op, long long args);
|
||||
/* syscall 341 has been skipped */
|
||||
/* syscall 342 has been skipped */
|
||||
void __sanitizer_syscall_pre_impl_rasctl(long long addr, long long len,
|
||||
long long op);
|
||||
void __sanitizer_syscall_post_impl_rasctl(long long res, long long addr,
|
||||
|
|
|
|||
|
|
@ -158,8 +158,8 @@ struct XRayLogImpl {
|
|||
/// The log initialization routine provided by the implementation, always
|
||||
/// provided with the following parameters:
|
||||
///
|
||||
/// - buffer size
|
||||
/// - maximum number of buffers
|
||||
/// - buffer size (unused)
|
||||
/// - maximum number of buffers (unused)
|
||||
/// - a pointer to an argument struct that the implementation MUST handle
|
||||
/// - the size of the argument struct
|
||||
///
|
||||
|
|
@ -355,25 +355,4 @@ XRayLogFlushStatus __xray_log_process_buffers(void (*Processor)(const char *,
|
|||
|
||||
} // extern "C"
|
||||
|
||||
namespace __xray {
|
||||
|
||||
/// DEPRECATED: Use __xray_log_init_mode(...) instead, and provide flag
|
||||
/// configuration strings to set the options instead.
|
||||
/// Options used by the LLVM XRay FDR logging implementation.
|
||||
struct FDRLoggingOptions {
|
||||
bool ReportErrors = false;
|
||||
int Fd = -1;
|
||||
};
|
||||
|
||||
/// DEPRECATED: Use __xray_log_init_mode(...) instead, and provide flag
|
||||
/// configuration strings to set the options instead.
|
||||
/// Options used by the LLVM XRay Basic (Naive) logging implementation.
|
||||
struct BasicLoggingOptions {
|
||||
int DurationFilterMicros = 0;
|
||||
size_t MaxStackDepth = 0;
|
||||
size_t ThreadBufferSize = 0;
|
||||
};
|
||||
|
||||
} // namespace __xray
|
||||
|
||||
#endif // XRAY_XRAY_LOG_INTERFACE_H
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ const uptr kAllocatorSpace = 0x600000000000ULL;
|
|||
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
|
||||
typedef DefaultSizeClassMap SizeClassMap;
|
||||
# endif
|
||||
template <typename AddressSpaceViewTy>
|
||||
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
|
||||
static const uptr kSpaceBeg = kAllocatorSpace;
|
||||
static const uptr kSpaceSize = kAllocatorSize;
|
||||
|
|
@ -155,37 +156,57 @@ struct AP64 { // Allocator64 parameters. Deliberately using a short name.
|
|||
typedef __asan::SizeClassMap SizeClassMap;
|
||||
typedef AsanMapUnmapCallback MapUnmapCallback;
|
||||
static const uptr kFlags = 0;
|
||||
using AddressSpaceView = AddressSpaceViewTy;
|
||||
};
|
||||
|
||||
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
|
||||
template <typename AddressSpaceView>
|
||||
using PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
|
||||
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
|
||||
#else // Fallback to SizeClassAllocator32.
|
||||
static const uptr kRegionSizeLog = 20;
|
||||
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
||||
# if SANITIZER_WORDSIZE == 32
|
||||
typedef FlatByteMap<kNumRegions> ByteMap;
|
||||
template <typename AddressSpaceView>
|
||||
using ByteMapASVT = FlatByteMap<kNumRegions, AddressSpaceView>;
|
||||
# elif SANITIZER_WORDSIZE == 64
|
||||
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
|
||||
template <typename AddressSpaceView>
|
||||
using ByteMapASVT =
|
||||
TwoLevelByteMap<(kNumRegions >> 12), 1 << 12, AddressSpaceView>;
|
||||
# endif
|
||||
typedef CompactSizeClassMap SizeClassMap;
|
||||
template <typename AddressSpaceViewTy>
|
||||
struct AP32 {
|
||||
static const uptr kSpaceBeg = 0;
|
||||
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
|
||||
static const uptr kMetadataSize = 16;
|
||||
typedef __asan::SizeClassMap SizeClassMap;
|
||||
static const uptr kRegionSizeLog = __asan::kRegionSizeLog;
|
||||
typedef __asan::ByteMap ByteMap;
|
||||
using AddressSpaceView = AddressSpaceViewTy;
|
||||
using ByteMap = __asan::ByteMapASVT<AddressSpaceView>;
|
||||
typedef AsanMapUnmapCallback MapUnmapCallback;
|
||||
static const uptr kFlags = 0;
|
||||
};
|
||||
typedef SizeClassAllocator32<AP32> PrimaryAllocator;
|
||||
template <typename AddressSpaceView>
|
||||
using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView> >;
|
||||
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
|
||||
#endif // SANITIZER_CAN_USE_ALLOCATOR64
|
||||
|
||||
static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
|
||||
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
||||
typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
|
||||
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
|
||||
SecondaryAllocator> AsanAllocator;
|
||||
template <typename AddressSpaceView>
|
||||
using AllocatorCacheASVT =
|
||||
SizeClassAllocatorLocalCache<PrimaryAllocatorASVT<AddressSpaceView>>;
|
||||
using AllocatorCache = AllocatorCacheASVT<LocalAddressSpaceView>;
|
||||
|
||||
template <typename AddressSpaceView>
|
||||
using SecondaryAllocatorASVT =
|
||||
LargeMmapAllocator<AsanMapUnmapCallback, DefaultLargeMmapAllocatorPtrArray,
|
||||
AddressSpaceView>;
|
||||
template <typename AddressSpaceView>
|
||||
using AsanAllocatorASVT =
|
||||
CombinedAllocator<PrimaryAllocatorASVT<AddressSpaceView>,
|
||||
AllocatorCacheASVT<AddressSpaceView>,
|
||||
SecondaryAllocatorASVT<AddressSpaceView>>;
|
||||
using AsanAllocator = AsanAllocatorASVT<LocalAddressSpaceView>;
|
||||
|
||||
struct AsanThreadLocalMallocStorage {
|
||||
uptr quarantine_cache[16];
|
||||
|
|
|
|||
|
|
@ -125,9 +125,8 @@ void ErrorAllocTypeMismatch::Print() {
|
|||
Decorator d;
|
||||
Printf("%s", d.Error());
|
||||
Report("ERROR: AddressSanitizer: %s (%s vs %s) on %p\n",
|
||||
scariness.GetDescription(),
|
||||
alloc_names[alloc_type], dealloc_names[dealloc_type],
|
||||
addr_description.addr);
|
||||
scariness.GetDescription(), alloc_names[alloc_type],
|
||||
dealloc_names[dealloc_type], addr_description.Address());
|
||||
Printf("%s", d.Default());
|
||||
CHECK_GT(dealloc_stack->size, 0);
|
||||
scariness.Print();
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@ struct ErrorFreeNotMalloced : ErrorBase {
|
|||
|
||||
struct ErrorAllocTypeMismatch : ErrorBase {
|
||||
const BufferedStackTrace *dealloc_stack;
|
||||
HeapAddressDescription addr_description;
|
||||
AllocType alloc_type, dealloc_type;
|
||||
AddressDescription addr_description;
|
||||
|
||||
ErrorAllocTypeMismatch() = default; // (*)
|
||||
ErrorAllocTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
|
||||
|
|
@ -119,9 +119,8 @@ struct ErrorAllocTypeMismatch : ErrorBase {
|
|||
: ErrorBase(tid, 10, "alloc-dealloc-mismatch"),
|
||||
dealloc_stack(stack),
|
||||
alloc_type(alloc_type_),
|
||||
dealloc_type(dealloc_type_) {
|
||||
GetHeapAddressInformation(addr, 1, &addr_description);
|
||||
};
|
||||
dealloc_type(dealloc_type_),
|
||||
addr_description(addr, 1, false) {}
|
||||
void Print();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -152,8 +152,6 @@ ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
|
|||
ASAN_FLAG(bool, halt_on_error, true,
|
||||
"Crash the program after printing the first error report "
|
||||
"(WARNING: USE AT YOUR OWN RISK!)")
|
||||
ASAN_FLAG(bool, use_odr_indicator, false,
|
||||
"Use special ODR indicator symbol for ODR violation detection")
|
||||
ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true,
|
||||
"realloc(p, 0) is equivalent to free(p) by default (Same as the "
|
||||
"POSIX standard). If set to false, realloc(p, 0) will return a "
|
||||
|
|
|
|||
|
|
@ -190,6 +190,13 @@ static void ThreadExitHook(void *hook, uptr os_id) {
|
|||
AsanThread::TSDDtor(per_thread);
|
||||
}
|
||||
|
||||
bool HandleDlopenInit() {
|
||||
// Not supported on this platform.
|
||||
static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
|
||||
"Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// These are declared (in extern "C") by <zircon/sanitizer.h>.
|
||||
|
|
|
|||
|
|
@ -83,9 +83,11 @@ static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
|
|||
}
|
||||
|
||||
static void ReportGlobal(const Global &g, const char *prefix) {
|
||||
Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
|
||||
prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
|
||||
g.module_name, g.has_dynamic_init);
|
||||
Report(
|
||||
"%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu "
|
||||
"odr_indicator=%p\n",
|
||||
prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
|
||||
g.module_name, g.has_dynamic_init, (void *)g.odr_indicator);
|
||||
if (g.location) {
|
||||
Report(" location (%p): name=%s[%p], %d %d\n", g.location,
|
||||
g.location->filename, g.location->filename, g.location->line_no,
|
||||
|
|
@ -133,6 +135,9 @@ enum GlobalSymbolState {
|
|||
// this method in case compiler instruments global variables through their
|
||||
// local aliases.
|
||||
static void CheckODRViolationViaIndicator(const Global *g) {
|
||||
// Instrumentation requests to skip ODR check.
|
||||
if (g->odr_indicator == UINTPTR_MAX)
|
||||
return;
|
||||
u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
|
||||
if (*odr_indicator == UNREGISTERED) {
|
||||
*odr_indicator = REGISTERED;
|
||||
|
|
@ -183,9 +188,7 @@ static void CheckODRViolationViaPoisoning(const Global *g) {
|
|||
// This routine chooses between two different methods of ODR violation
|
||||
// detection.
|
||||
static inline bool UseODRIndicator(const Global *g) {
|
||||
// Use ODR indicator method iff use_odr_indicator flag is set and
|
||||
// indicator symbol address is not 0.
|
||||
return flags()->use_odr_indicator && g->odr_indicator > 0;
|
||||
return g->odr_indicator > 0;
|
||||
}
|
||||
|
||||
// Register a global variable.
|
||||
|
|
@ -248,7 +251,7 @@ static void UnregisterGlobal(const Global *g) {
|
|||
// implementation. It might not be worth doing anyway.
|
||||
|
||||
// Release ODR indicator.
|
||||
if (UseODRIndicator(g)) {
|
||||
if (UseODRIndicator(g) && g->odr_indicator != UINTPTR_MAX) {
|
||||
u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
|
||||
*odr_indicator = UNREGISTERED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ static void call_on_globals(void (*hook)(__asan_global *, uptr)) {
|
|||
__asan_global *end = &__asan_globals_end;
|
||||
uptr bytediff = (uptr)end - (uptr)start;
|
||||
if (bytediff % sizeof(__asan_global) != 0) {
|
||||
#ifdef SANITIZER_DLL_THUNK
|
||||
#if defined(SANITIZER_DLL_THUNK) || defined(SANITIZER_DYNAMIC_RUNTIME_THUNK)
|
||||
__debugbreak();
|
||||
#else
|
||||
CHECK("corrupt asan global array");
|
||||
|
|
|
|||
|
|
@ -111,6 +111,11 @@ 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.
|
||||
bool HandleDlopenInit();
|
||||
|
||||
// Add convenient macro for interface functions that may be represented as
|
||||
// weak hooks.
|
||||
#define ASAN_MALLOC_HOOK(ptr, size) \
|
||||
|
|
|
|||
|
|
@ -248,6 +248,13 @@ void *AsanDlSymNext(const char *sym) {
|
|||
return dlsym(RTLD_NEXT, sym);
|
||||
}
|
||||
|
||||
bool HandleDlopenInit() {
|
||||
// Not supported on this platform.
|
||||
static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
|
||||
"Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
|
|||
}
|
||||
|
||||
INTERCEPTOR(int, mallopt, int cmd, int value) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
#endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
|
||||
|
||||
|
|
|
|||
|
|
@ -61,4 +61,25 @@ using namespace __asan;
|
|||
|
||||
#include "sanitizer_common/sanitizer_malloc_mac.inc"
|
||||
|
||||
namespace COMMON_MALLOC_NAMESPACE {
|
||||
bool HandleDlopenInit() {
|
||||
static_assert(SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
|
||||
"Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be true");
|
||||
// We have no reliable way of knowing how we are being loaded
|
||||
// so make it a requirement on Apple platforms to set this environment
|
||||
// variable to indicate that we want to perform initialization via
|
||||
// dlopen().
|
||||
auto init_str = GetEnv("APPLE_ASAN_INIT_FOR_DLOPEN");
|
||||
if (!init_str)
|
||||
return false;
|
||||
if (internal_strncmp(init_str, "1", 1) != 0)
|
||||
return false;
|
||||
// When we are loaded via `dlopen()` path we still initialize the malloc zone
|
||||
// so Symbolication clients (e.g. `leaks`) that load the ASan allocator can
|
||||
// find an initialized malloc zone.
|
||||
InitMallocZoneFields();
|
||||
return true;
|
||||
}
|
||||
} // namespace COMMON_MALLOC_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,8 +14,17 @@
|
|||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
// Intentionally not including windows.h here, to avoid the risk of
|
||||
// pulling in conflicting declarations of these functions. (With mingw-w64,
|
||||
// there's a risk of windows.h pulling in stdint.h.)
|
||||
typedef int BOOL;
|
||||
typedef void *HANDLE;
|
||||
typedef const void *LPCVOID;
|
||||
typedef void *LPVOID;
|
||||
|
||||
#define HEAP_ZERO_MEMORY 0x00000008
|
||||
#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010
|
||||
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
|
|
@ -125,12 +134,17 @@ void *_recalloc_base(void *p, size_t n, size_t elem_size) {
|
|||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
size_t _msize(const void *ptr) {
|
||||
size_t _msize(void *ptr) {
|
||||
GET_CURRENT_PC_BP_SP;
|
||||
(void)sp;
|
||||
return asan_malloc_usable_size(ptr, pc, bp);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
size_t _msize_base(void *ptr) {
|
||||
return _msize(ptr);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_expand(void *memblock, size_t size) {
|
||||
// _expand is used in realloc-like functions to resize the buffer if possible.
|
||||
|
|
@ -226,6 +240,7 @@ void ReplaceSystemMalloc() {
|
|||
TryToOverrideFunction("_recalloc_base", (uptr)_recalloc);
|
||||
TryToOverrideFunction("_recalloc_crt", (uptr)_recalloc);
|
||||
TryToOverrideFunction("_msize", (uptr)_msize);
|
||||
TryToOverrideFunction("_msize_base", (uptr)_msize);
|
||||
TryToOverrideFunction("_expand", (uptr)_expand);
|
||||
TryToOverrideFunction("_expand_base", (uptr)_expand);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
// anyway by passing extra -export flags to the linker, which is exactly that
|
||||
// dllexport would normally do. We need to export them in order to make the
|
||||
// VS2015 dynamic CRT (MD) work.
|
||||
#if SANITIZER_WINDOWS
|
||||
#if SANITIZER_WINDOWS && defined(_MSC_VER)
|
||||
#define CXX_OPERATOR_ATTRIBUTE
|
||||
#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym))
|
||||
#ifdef _WIN64
|
||||
|
|
|
|||
|
|
@ -40,6 +40,51 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
|
|||
|
||||
// ---------------------- TSD ---------------- {{{1
|
||||
|
||||
#if SANITIZER_NETBSD || SANITIZER_FREEBSD
|
||||
// Thread Static Data cannot be used in early init on NetBSD and FreeBSD.
|
||||
// Reuse the Asan TSD API for compatibility with existing code
|
||||
// with an alternative implementation.
|
||||
|
||||
static void (*tsd_destructor)(void *tsd) = nullptr;
|
||||
|
||||
struct tsd_key {
|
||||
tsd_key() : key(nullptr) {}
|
||||
~tsd_key() {
|
||||
CHECK(tsd_destructor);
|
||||
if (key)
|
||||
(*tsd_destructor)(key);
|
||||
}
|
||||
void *key;
|
||||
};
|
||||
|
||||
static thread_local struct tsd_key key;
|
||||
|
||||
void AsanTSDInit(void (*destructor)(void *tsd)) {
|
||||
CHECK(!tsd_destructor);
|
||||
tsd_destructor = destructor;
|
||||
}
|
||||
|
||||
void *AsanTSDGet() {
|
||||
CHECK(tsd_destructor);
|
||||
return key.key;
|
||||
}
|
||||
|
||||
void AsanTSDSet(void *tsd) {
|
||||
CHECK(tsd_destructor);
|
||||
CHECK(tsd);
|
||||
CHECK(!key.key);
|
||||
key.key = tsd;
|
||||
}
|
||||
|
||||
void PlatformTSDDtor(void *tsd) {
|
||||
CHECK(tsd_destructor);
|
||||
CHECK_EQ(key.key, tsd);
|
||||
key.key = nullptr;
|
||||
// Make sure that signal handler can not see a stale current thread pointer.
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
AsanThread::TSDDtor(tsd);
|
||||
}
|
||||
#else
|
||||
static pthread_key_t tsd_key;
|
||||
static bool tsd_key_inited = false;
|
||||
void AsanTSDInit(void (*destructor)(void *tsd)) {
|
||||
|
|
@ -67,6 +112,7 @@ void PlatformTSDDtor(void *tsd) {
|
|||
}
|
||||
AsanThread::TSDDtor(tsd);
|
||||
}
|
||||
#endif
|
||||
} // namespace __asan
|
||||
|
||||
#endif // SANITIZER_POSIX
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
// ASan-private header for error reporting functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ASAN_REPORT_H
|
||||
#define ASAN_REPORT_H
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_thread.h"
|
||||
|
|
@ -92,3 +95,4 @@ void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
|
|||
BufferedStackTrace *stack);
|
||||
|
||||
} // namespace __asan
|
||||
#endif // ASAN_REPORT_H
|
||||
|
|
|
|||
|
|
@ -213,6 +213,12 @@ static void HandleExit() {
|
|||
}
|
||||
}
|
||||
|
||||
bool HandleDlopenInit() {
|
||||
// Not supported on this platform.
|
||||
static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
|
||||
"Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
|
||||
return false;
|
||||
}
|
||||
} // namespace __asan
|
||||
|
||||
// These are declared (in extern "C") by <some_path/sanitizer.h>.
|
||||
|
|
|
|||
|
|
@ -383,6 +383,19 @@ void PrintAddressSpaceLayout() {
|
|||
kHighShadowBeg > kMidMemEnd);
|
||||
}
|
||||
|
||||
#if defined(__thumb__) && defined(__linux__)
|
||||
#define START_BACKGROUND_THREAD_IN_ASAN_INTERNAL
|
||||
#endif
|
||||
|
||||
#ifndef START_BACKGROUND_THREAD_IN_ASAN_INTERNAL
|
||||
static bool UNUSED __local_asan_dyninit = [] {
|
||||
MaybeStartBackgroudThread();
|
||||
SetSoftRssLimitExceededCallback(AsanSoftRssLimitExceededCallback);
|
||||
|
||||
return false;
|
||||
}();
|
||||
#endif
|
||||
|
||||
static void AsanInitInternal() {
|
||||
if (LIKELY(asan_inited)) return;
|
||||
SanitizerToolName = "AddressSanitizer";
|
||||
|
|
@ -396,6 +409,14 @@ static void AsanInitInternal() {
|
|||
// initialization steps look at flags().
|
||||
InitializeFlags();
|
||||
|
||||
// Stop performing init at this point if we are being loaded via
|
||||
// dlopen() and the platform supports it.
|
||||
if (SANITIZER_SUPPORTS_INIT_FOR_DLOPEN && UNLIKELY(HandleDlopenInit())) {
|
||||
asan_init_is_running = false;
|
||||
VReport(1, "AddressSanitizer init is being performed for dlopen().\n");
|
||||
return;
|
||||
}
|
||||
|
||||
AsanCheckIncompatibleRT();
|
||||
AsanCheckDynamicRTPrereqs();
|
||||
AvoidCVE_2016_2143();
|
||||
|
|
@ -420,6 +441,8 @@ static void AsanInitInternal() {
|
|||
__asan_option_detect_stack_use_after_return =
|
||||
flags()->detect_stack_use_after_return;
|
||||
|
||||
__sanitizer::InitializePlatformEarly();
|
||||
|
||||
// Re-exec ourselves if we need to set additional env or command line args.
|
||||
MaybeReexec();
|
||||
|
||||
|
|
@ -447,8 +470,10 @@ static void AsanInitInternal() {
|
|||
allocator_options.SetFrom(flags(), common_flags());
|
||||
InitializeAllocator(allocator_options);
|
||||
|
||||
#ifdef START_BACKGROUND_THREAD_IN_ASAN_INTERNAL
|
||||
MaybeStartBackgroudThread();
|
||||
SetSoftRssLimitExceededCallback(AsanSoftRssLimitExceededCallback);
|
||||
#endif
|
||||
|
||||
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
|
||||
// should be set to 1 prior to initializing the threads.
|
||||
|
|
|
|||
|
|
@ -223,9 +223,11 @@ void AsanThread::Init(const InitOptions *options) {
|
|||
atomic_store(&stack_switching_, false, memory_order_release);
|
||||
CHECK_EQ(this->stack_size(), 0U);
|
||||
SetThreadStackAndTls(options);
|
||||
CHECK_GT(this->stack_size(), 0U);
|
||||
CHECK(AddrIsInMem(stack_bottom_));
|
||||
CHECK(AddrIsInMem(stack_top_ - 1));
|
||||
if (stack_top_ != stack_bottom_) {
|
||||
CHECK_GT(this->stack_size(), 0U);
|
||||
CHECK(AddrIsInMem(stack_bottom_));
|
||||
CHECK(AddrIsInMem(stack_top_ - 1));
|
||||
}
|
||||
ClearShadowForThreadStackAndTLS();
|
||||
fake_stack_ = nullptr;
|
||||
if (__asan_option_detect_stack_use_after_return)
|
||||
|
|
@ -289,20 +291,23 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
|
|||
DCHECK_EQ(options, nullptr);
|
||||
uptr tls_size = 0;
|
||||
uptr stack_size = 0;
|
||||
GetThreadStackAndTls(tid() == 0, const_cast<uptr *>(&stack_bottom_),
|
||||
const_cast<uptr *>(&stack_size), &tls_begin_, &tls_size);
|
||||
GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
|
||||
&tls_size);
|
||||
stack_top_ = stack_bottom_ + stack_size;
|
||||
tls_end_ = tls_begin_ + tls_size;
|
||||
dtls_ = DTLS_Get();
|
||||
|
||||
int local;
|
||||
CHECK(AddrIsInStack((uptr)&local));
|
||||
if (stack_top_ != stack_bottom_) {
|
||||
int local;
|
||||
CHECK(AddrIsInStack((uptr)&local));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
|
||||
|
||||
void AsanThread::ClearShadowForThreadStackAndTLS() {
|
||||
PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
|
||||
if (stack_top_ != stack_bottom_)
|
||||
PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
|
||||
if (tls_begin_ != tls_end_) {
|
||||
uptr tls_begin_aligned = RoundDownTo(tls_begin_, SHADOW_GRANULARITY);
|
||||
uptr tls_end_aligned = RoundUpTo(tls_end_, SHADOW_GRANULARITY);
|
||||
|
|
@ -314,6 +319,9 @@ void AsanThread::ClearShadowForThreadStackAndTLS() {
|
|||
|
||||
bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
|
||||
StackFrameAccess *access) {
|
||||
if (stack_top_ == stack_bottom_)
|
||||
return false;
|
||||
|
||||
uptr bottom = 0;
|
||||
if (AddrIsInStack(addr)) {
|
||||
bottom = stack_bottom();
|
||||
|
|
|
|||
|
|
@ -159,6 +159,14 @@ INTERCEPTOR_WINAPI(DWORD, CreateThread,
|
|||
namespace __asan {
|
||||
|
||||
void InitializePlatformInterceptors() {
|
||||
// The interceptors were not designed to be removable, so we have to keep this
|
||||
// module alive for the life of the process.
|
||||
HMODULE pinned;
|
||||
CHECK(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||
GET_MODULE_HANDLE_EX_FLAG_PIN,
|
||||
(LPCWSTR)&InitializePlatformInterceptors,
|
||||
&pinned));
|
||||
|
||||
ASAN_INTERCEPT_FUNC(CreateThread);
|
||||
ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter);
|
||||
|
||||
|
|
@ -314,6 +322,13 @@ int __asan_set_seh_filter() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool HandleDlopenInit() {
|
||||
// Not supported on this platform.
|
||||
static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
|
||||
"Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !ASAN_DYNAMIC
|
||||
// The CRT runs initializers in this order:
|
||||
// - C initializers, from XIA to XIZ
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ INTERCEPT_WRAP_W_WWW(_recalloc)
|
|||
INTERCEPT_WRAP_W_WWW(_recalloc_base)
|
||||
|
||||
INTERCEPT_WRAP_W_W(_msize)
|
||||
INTERCEPT_WRAP_W_W(_msize_base)
|
||||
INTERCEPT_WRAP_W_W(_expand)
|
||||
INTERCEPT_WRAP_W_W(_expand_dbg)
|
||||
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ LOCAL_LABEL(do_substraction):
|
|||
|
||||
push {r0, r1, r2, r3}
|
||||
movs r0, r4
|
||||
bl __clzsi2
|
||||
bl SYMBOL_NAME(__clzsi2)
|
||||
movs r5, r0
|
||||
pop {r0, r1, r2, r3}
|
||||
// shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
|
|||
mov ip, #APSR_C
|
||||
msr APSR_nzcvq, ip
|
||||
#else
|
||||
msr CPSR_f, #APSR_C
|
||||
msr APSR_nzcvq, #APSR_C
|
||||
#endif
|
||||
JMP(lr)
|
||||
#endif
|
||||
|
|
@ -115,11 +115,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple)
|
|||
movne ip, #(APSR_C)
|
||||
|
||||
1:
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
msr APSR_nzcvq, ip
|
||||
#else
|
||||
msr CPSR_f, ip
|
||||
#endif
|
||||
pop {r0-r3}
|
||||
POP_PC()
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
|
|||
mov ip, #APSR_C
|
||||
msr APSR_nzcvq, ip
|
||||
#else
|
||||
msr CPSR_f, #APSR_C
|
||||
msr APSR_nzcvq, #APSR_C
|
||||
#endif
|
||||
JMP(lr)
|
||||
#endif
|
||||
|
|
@ -115,11 +115,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple)
|
|||
movne ip, #(APSR_C)
|
||||
|
||||
1:
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
msr APSR_nzcvq, ip
|
||||
#else
|
||||
msr CPSR_f, ip
|
||||
#endif
|
||||
pop {r0-r3}
|
||||
POP_PC()
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,8 +16,13 @@
|
|||
|
||||
/* Returns: the number of leading 0-bits */
|
||||
|
||||
#if !defined(__clang__) && (defined(__sparc64__) || defined(__mips64) || defined(__riscv__))
|
||||
/* gcc resolves __builtin_clz -> __clzdi2 leading to infinite recursion */
|
||||
#if !defined(__clang__) && \
|
||||
((defined(__sparc__) && defined(__arch64__)) || \
|
||||
defined(__mips64) || \
|
||||
(defined(__riscv) && __SIZEOF_POINTER__ >= 8))
|
||||
/* On 64-bit architectures with neither a native clz instruction nor a native
|
||||
* 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);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@ enum ProcessorTypes {
|
|||
AMD_BTVER2,
|
||||
AMDFAM17H,
|
||||
INTEL_KNM,
|
||||
INTEL_GOLDMONT,
|
||||
INTEL_GOLDMONT_PLUS,
|
||||
INTEL_TREMONT,
|
||||
CPU_TYPE_MAX
|
||||
};
|
||||
|
||||
|
|
@ -76,6 +79,8 @@ enum ProcessorSubtypes {
|
|||
INTEL_COREI7_SKYLAKE,
|
||||
INTEL_COREI7_SKYLAKE_AVX512,
|
||||
INTEL_COREI7_CANNONLAKE,
|
||||
INTEL_COREI7_ICELAKE_CLIENT,
|
||||
INTEL_COREI7_ICELAKE_SERVER,
|
||||
CPU_SUBTYPE_MAX
|
||||
};
|
||||
|
||||
|
|
@ -110,7 +115,12 @@ enum ProcessorFeatures {
|
|||
FEATURE_AVX512IFMA,
|
||||
FEATURE_AVX5124VNNIW,
|
||||
FEATURE_AVX5124FMAPS,
|
||||
FEATURE_AVX512VPOPCNTDQ
|
||||
FEATURE_AVX512VPOPCNTDQ,
|
||||
FEATURE_AVX512VBMI2,
|
||||
FEATURE_GFNI,
|
||||
FEATURE_VPCLMULQDQ,
|
||||
FEATURE_AVX512VNNI,
|
||||
FEATURE_AVX512BITALG
|
||||
};
|
||||
|
||||
// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).
|
||||
|
|
@ -364,6 +374,14 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
|
|||
case 0x4c: // really airmont
|
||||
*Type = INTEL_SILVERMONT;
|
||||
break; // "silvermont"
|
||||
// Goldmont:
|
||||
case 0x5c: // Apollo Lake
|
||||
case 0x5f: // Denverton
|
||||
*Type = INTEL_GOLDMONT;
|
||||
break; // "goldmont"
|
||||
case 0x7a:
|
||||
*Type = INTEL_GOLDMONT_PLUS;
|
||||
break;
|
||||
|
||||
case 0x57:
|
||||
*Type = INTEL_KNL; // knl
|
||||
|
|
@ -438,35 +456,45 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
|
|||
}
|
||||
|
||||
static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
|
||||
unsigned *FeaturesOut) {
|
||||
unsigned *FeaturesOut,
|
||||
unsigned *Features2Out) {
|
||||
unsigned Features = 0;
|
||||
unsigned Features2 = 0;
|
||||
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)
|
||||
|
||||
if ((EDX >> 15) & 1)
|
||||
Features |= 1 << FEATURE_CMOV;
|
||||
setFeature(FEATURE_CMOV);
|
||||
if ((EDX >> 23) & 1)
|
||||
Features |= 1 << FEATURE_MMX;
|
||||
setFeature(FEATURE_MMX);
|
||||
if ((EDX >> 25) & 1)
|
||||
Features |= 1 << FEATURE_SSE;
|
||||
setFeature(FEATURE_SSE);
|
||||
if ((EDX >> 26) & 1)
|
||||
Features |= 1 << FEATURE_SSE2;
|
||||
setFeature(FEATURE_SSE2);
|
||||
|
||||
if ((ECX >> 0) & 1)
|
||||
Features |= 1 << FEATURE_SSE3;
|
||||
setFeature(FEATURE_SSE3);
|
||||
if ((ECX >> 1) & 1)
|
||||
Features |= 1 << FEATURE_PCLMUL;
|
||||
setFeature(FEATURE_PCLMUL);
|
||||
if ((ECX >> 9) & 1)
|
||||
Features |= 1 << FEATURE_SSSE3;
|
||||
setFeature(FEATURE_SSSE3);
|
||||
if ((ECX >> 12) & 1)
|
||||
Features |= 1 << FEATURE_FMA;
|
||||
setFeature(FEATURE_FMA);
|
||||
if ((ECX >> 19) & 1)
|
||||
Features |= 1 << FEATURE_SSE4_1;
|
||||
setFeature(FEATURE_SSE4_1);
|
||||
if ((ECX >> 20) & 1)
|
||||
Features |= 1 << FEATURE_SSE4_2;
|
||||
setFeature(FEATURE_SSE4_2);
|
||||
if ((ECX >> 23) & 1)
|
||||
Features |= 1 << FEATURE_POPCNT;
|
||||
setFeature(FEATURE_POPCNT);
|
||||
if ((ECX >> 25) & 1)
|
||||
Features |= 1 << FEATURE_AES;
|
||||
setFeature(FEATURE_AES);
|
||||
|
||||
// If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV
|
||||
// indicates that the AVX registers will be saved and restored on context
|
||||
|
|
@ -477,43 +505,53 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
|
|||
bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0);
|
||||
|
||||
if (HasAVX)
|
||||
Features |= 1 << FEATURE_AVX;
|
||||
setFeature(FEATURE_AVX);
|
||||
|
||||
bool HasLeaf7 =
|
||||
MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);
|
||||
|
||||
if (HasLeaf7 && ((EBX >> 3) & 1))
|
||||
Features |= 1 << FEATURE_BMI;
|
||||
setFeature(FEATURE_BMI);
|
||||
if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX)
|
||||
Features |= 1 << FEATURE_AVX2;
|
||||
setFeature(FEATURE_AVX2);
|
||||
if (HasLeaf7 && ((EBX >> 9) & 1))
|
||||
Features |= 1 << FEATURE_BMI2;
|
||||
setFeature(FEATURE_BMI2);
|
||||
if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX512F;
|
||||
setFeature(FEATURE_AVX512F);
|
||||
if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX512DQ;
|
||||
setFeature(FEATURE_AVX512DQ);
|
||||
if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX512IFMA;
|
||||
setFeature(FEATURE_AVX512IFMA);
|
||||
if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX512PF;
|
||||
setFeature(FEATURE_AVX512PF);
|
||||
if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX512ER;
|
||||
setFeature(FEATURE_AVX512ER);
|
||||
if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX512CD;
|
||||
setFeature(FEATURE_AVX512CD);
|
||||
if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX512BW;
|
||||
setFeature(FEATURE_AVX512BW);
|
||||
if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX512VL;
|
||||
setFeature(FEATURE_AVX512VL);
|
||||
|
||||
if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX512VBMI;
|
||||
setFeature(FEATURE_AVX512VBMI);
|
||||
if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save)
|
||||
setFeature(FEATURE_AVX512VBMI2);
|
||||
if (HasLeaf7 && ((ECX >> 8) & 1))
|
||||
setFeature(FEATURE_GFNI);
|
||||
if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVX)
|
||||
setFeature(FEATURE_VPCLMULQDQ);
|
||||
if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save)
|
||||
setFeature(FEATURE_AVX512VNNI);
|
||||
if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save)
|
||||
setFeature(FEATURE_AVX512BITALG);
|
||||
if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX512VPOPCNTDQ;
|
||||
setFeature(FEATURE_AVX512VPOPCNTDQ);
|
||||
|
||||
if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX5124VNNIW;
|
||||
setFeature(FEATURE_AVX5124VNNIW);
|
||||
if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save)
|
||||
Features |= 1 << FEATURE_AVX5124FMAPS;
|
||||
setFeature(FEATURE_AVX5124FMAPS);
|
||||
|
||||
unsigned MaxExtLevel;
|
||||
getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX);
|
||||
|
|
@ -521,13 +559,15 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
|
|||
bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 &&
|
||||
!getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
|
||||
if (HasExtLeaf1 && ((ECX >> 6) & 1))
|
||||
Features |= 1 << FEATURE_SSE4_A;
|
||||
setFeature(FEATURE_SSE4_A);
|
||||
if (HasExtLeaf1 && ((ECX >> 11) & 1))
|
||||
Features |= 1 << FEATURE_XOP;
|
||||
setFeature(FEATURE_XOP);
|
||||
if (HasExtLeaf1 && ((ECX >> 16) & 1))
|
||||
Features |= 1 << FEATURE_FMA4;
|
||||
setFeature(FEATURE_FMA4);
|
||||
|
||||
*FeaturesOut = Features;
|
||||
*Features2Out = Features2;
|
||||
#undef setFeature
|
||||
}
|
||||
|
||||
#if defined(HAVE_INIT_PRIORITY)
|
||||
|
|
@ -548,8 +588,9 @@ struct __processor_model {
|
|||
unsigned int __cpu_subtype;
|
||||
unsigned int __cpu_features[1];
|
||||
} __cpu_model = {0, 0, 0, {0}};
|
||||
unsigned int __cpu_features2;
|
||||
|
||||
/* A constructor function that is sets __cpu_model and __cpu_features with
|
||||
/* A constructor function that is sets __cpu_model and __cpu_features2 with
|
||||
the right values. This needs to run only once. This constructor is
|
||||
given the highest priority and it should run before constructors without
|
||||
the priority set. However, it still runs after ifunc initializers and
|
||||
|
|
@ -562,6 +603,7 @@ __cpu_indicator_init(void) {
|
|||
unsigned Vendor;
|
||||
unsigned Model, Family, Brand_id;
|
||||
unsigned Features = 0;
|
||||
unsigned Features2 = 0;
|
||||
|
||||
/* This function needs to run just once. */
|
||||
if (__cpu_model.__cpu_vendor)
|
||||
|
|
@ -580,8 +622,9 @@ __cpu_indicator_init(void) {
|
|||
Brand_id = EBX & 0xff;
|
||||
|
||||
/* Find available features. */
|
||||
getAvailableFeatures(ECX, EDX, MaxLeaf, &Features);
|
||||
getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2);
|
||||
__cpu_model.__cpu_features[0] = Features;
|
||||
__cpu_features2 = Features2;
|
||||
|
||||
if (Vendor == SIG_INTEL) {
|
||||
/* Get CPU type. */
|
||||
|
|
|
|||
|
|
@ -16,8 +16,13 @@
|
|||
|
||||
/* Returns: the number of trailing 0-bits */
|
||||
|
||||
#if !defined(__clang__) && (defined(__sparc64__) || defined(__mips64) || defined(__riscv__))
|
||||
/* gcc resolves __builtin_ctz -> __ctzdi2 leading to infinite recursion */
|
||||
#if !defined(__clang__) && \
|
||||
((defined(__sparc__) && defined(__arch64__)) || \
|
||||
defined(__mips64) || \
|
||||
(defined(__riscv) && __SIZEOF_POINTER__ >= 8))
|
||||
/* On 64-bit architectures with neither a native clz instruction nor a native
|
||||
* 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);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#define DOUBLE_PRECISION
|
||||
#include "fp_lib.h"
|
||||
#include "int_lib.h"
|
||||
#include "int_math.h"
|
||||
|
||||
|
|
@ -21,7 +23,7 @@ COMPILER_RT_ABI Dcomplex
|
|||
__divdc3(double __a, double __b, double __c, double __d)
|
||||
{
|
||||
int __ilogbw = 0;
|
||||
double __logbw = crt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d)));
|
||||
double __logbw = __compiler_rt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d)));
|
||||
if (crt_isfinite(__logbw))
|
||||
{
|
||||
__ilogbw = (int)__logbw;
|
||||
|
|
|
|||
|
|
@ -21,36 +21,36 @@
|
|||
|
||||
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);
|
||||
|
|
@ -59,28 +59,28 @@ __divdf3(fp_t a, fp_t b) {
|
|||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
// Or in 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;
|
||||
|
||||
|
||||
// Now refine the reciprocal estimate using a Newton-Raphson iteration:
|
||||
//
|
||||
// x1 = x0 * (2 - x0 * b)
|
||||
|
|
@ -95,13 +95,13 @@ __divdf3(fp_t a, fp_t b) {
|
|||
recip32 = (uint64_t)recip32 * correction32 >> 31;
|
||||
correction32 = -((uint64_t)recip32 * q31b >> 32);
|
||||
recip32 = (uint64_t)recip32 * correction32 >> 31;
|
||||
|
||||
|
||||
// recip32 might have overflowed to exactly zero in the preceding
|
||||
// computation if the high word of b is exactly 1.0. This would sabotage
|
||||
// the full-width final stage of the computation that follows, so we adjust
|
||||
// recip32 downward 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;
|
||||
|
|
@ -110,14 +110,14 @@ __divdf3(fp_t a, fp_t b) {
|
|||
uint32_t cHi = correction >> 32;
|
||||
uint32_t cLo = correction;
|
||||
reciprocal = (uint64_t)recip32*cHi + ((uint64_t)recip32*cLo >> 32);
|
||||
|
||||
|
||||
// We already adjusted the 32-bit estimate, now we need to 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
|
||||
|
|
@ -127,12 +127,12 @@ __divdf3(fp_t a, fp_t 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
|
||||
//
|
||||
|
|
@ -141,7 +141,7 @@ __divdf3(fp_t a, fp_t 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)
|
||||
|
|
@ -154,20 +154,20 @@ __divdf3(fp_t a, fp_t b) {
|
|||
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);
|
||||
}
|
||||
|
||||
|
||||
else if (writtenExponent < 1) {
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
*===----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#define SINGLE_PRECISION
|
||||
#include "fp_lib.h"
|
||||
#include "int_lib.h"
|
||||
#include "int_math.h"
|
||||
|
||||
|
|
@ -21,7 +23,8 @@ COMPILER_RT_ABI Fcomplex
|
|||
__divsc3(float __a, float __b, float __c, float __d)
|
||||
{
|
||||
int __ilogbw = 0;
|
||||
float __logbw = crt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
|
||||
float __logbw =
|
||||
__compiler_rt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
|
||||
if (crt_isfinite(__logbw))
|
||||
{
|
||||
__ilogbw = (int)__logbw;
|
||||
|
|
|
|||
|
|
@ -21,36 +21,36 @@
|
|||
|
||||
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);
|
||||
|
|
@ -59,28 +59,28 @@ __divsf3(fp_t a, fp_t b) {
|
|||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
// Or in 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.
|
||||
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)
|
||||
|
|
@ -95,7 +95,7 @@ __divsf3(fp_t a, fp_t b) {
|
|||
reciprocal = (uint64_t)reciprocal * correction >> 31;
|
||||
correction = -((uint64_t)reciprocal * q31b >> 32);
|
||||
reciprocal = (uint64_t)reciprocal * correction >> 31;
|
||||
|
||||
|
||||
// Exhaustive testing shows that the error in reciprocal after three steps
|
||||
// is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our
|
||||
// expectations. We bump the reciprocal by a tiny value to force the error
|
||||
|
|
@ -103,7 +103,7 @@ __divsf3(fp_t a, fp_t b) {
|
|||
// be specific). This also causes 1/1 to give a sensible approximation
|
||||
// instead of zero (due to overflow).
|
||||
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
|
||||
|
|
@ -115,9 +115,9 @@ __divsf3(fp_t a, fp_t b) {
|
|||
// 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
|
||||
// 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
|
||||
//
|
||||
|
|
@ -126,7 +126,7 @@ __divsf3(fp_t a, fp_t 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)
|
||||
|
|
@ -141,18 +141,18 @@ __divsf3(fp_t a, fp_t b) {
|
|||
}
|
||||
|
||||
const int writtenExponent = quotientExponent + exponentBias;
|
||||
|
||||
|
||||
if (writtenExponent >= maxExponent) {
|
||||
// If we have overflowed the exponent, return infinity.
|
||||
return fromRep(infRep | quotientSign);
|
||||
}
|
||||
|
||||
|
||||
else if (writtenExponent < 1) {
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
*===----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#define QUAD_PRECISION
|
||||
#include "fp_lib.h"
|
||||
#include "int_lib.h"
|
||||
#include "int_math.h"
|
||||
|
||||
|
|
@ -21,7 +23,8 @@ COMPILER_RT_ABI Lcomplex
|
|||
__divtc3(long double __a, long double __b, long double __c, long double __d)
|
||||
{
|
||||
int __ilogbw = 0;
|
||||
long double __logbw = crt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
|
||||
long double __logbw =
|
||||
__compiler_rt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
|
||||
if (crt_isfinite(__logbw))
|
||||
{
|
||||
__ilogbw = (int)__logbw;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ static void emutls_shutdown(emutls_address_array *array);
|
|||
|
||||
static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_key_t emutls_pthread_key;
|
||||
static bool emutls_key_created = false;
|
||||
|
||||
typedef unsigned int gcc_word __attribute__((mode(word)));
|
||||
typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
|
||||
|
|
@ -109,6 +110,7 @@ static void emutls_key_destructor(void* ptr) {
|
|||
static __inline void emutls_init(void) {
|
||||
if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
|
||||
abort();
|
||||
emutls_key_created = true;
|
||||
}
|
||||
|
||||
static __inline void emutls_init_once(void) {
|
||||
|
|
@ -390,3 +392,14 @@ void* __emutls_get_address(__emutls_control* control) {
|
|||
array->data[index] = emutls_allocate_object(control);
|
||||
return array->data[index];
|
||||
}
|
||||
|
||||
#ifdef __BIONIC__
|
||||
/* Called by Bionic on dlclose to delete the emutls pthread key. */
|
||||
__attribute__((visibility("hidden")))
|
||||
void __emutls_unregister_key(void) {
|
||||
if (emutls_key_created) {
|
||||
pthread_key_delete(emutls_pthread_key);
|
||||
emutls_key_created = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include "int_lib.h"
|
||||
#include "int_math.h"
|
||||
|
||||
// x86_64 FreeBSD prior v9.3 define fixed-width types incorrectly in
|
||||
// 32-bit mode.
|
||||
|
|
@ -265,6 +266,62 @@ static __inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, unsigned int
|
|||
*hi = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Implements logb methods (logb, logbf, logbl) for IEEE-754. This avoids
|
||||
// pulling in a libm dependency from compiler-rt, but is not meant to replace
|
||||
// it (i.e. code calling logb() should get the one from libm, not this), hence
|
||||
// the __compiler_rt prefix.
|
||||
static __inline fp_t __compiler_rt_logbX(fp_t x) {
|
||||
rep_t rep = toRep(x);
|
||||
int exp = (rep & exponentMask) >> significandBits;
|
||||
|
||||
// Abnormal cases:
|
||||
// 1) +/- inf returns +inf; NaN returns NaN
|
||||
// 2) 0.0 returns -inf
|
||||
if (exp == maxExponent) {
|
||||
if (((rep & signBit) == 0) || (x != x)) {
|
||||
return x; // NaN or +inf: return x
|
||||
} else {
|
||||
return -x; // -inf: return -x
|
||||
}
|
||||
} else if (x == 0.0) {
|
||||
// 0.0: return -inf
|
||||
return fromRep(infRep | signBit);
|
||||
}
|
||||
|
||||
if (exp != 0) {
|
||||
// Normal number
|
||||
return exp - exponentBias; // Unbias exponent
|
||||
} else {
|
||||
// Subnormal number; normalize and repeat
|
||||
rep &= absMask;
|
||||
const int shift = 1 - normalize(&rep);
|
||||
exp = (rep & exponentMask) >> significandBits;
|
||||
return exp - exponentBias - shift; // Unbias exponent
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SINGLE_PRECISION)
|
||||
static __inline fp_t __compiler_rt_logbf(fp_t x) {
|
||||
return __compiler_rt_logbX(x);
|
||||
}
|
||||
#elif defined(DOUBLE_PRECISION)
|
||||
static __inline fp_t __compiler_rt_logb(fp_t x) {
|
||||
return __compiler_rt_logbX(x);
|
||||
}
|
||||
#elif defined(QUAD_PRECISION)
|
||||
#if defined(CRT_LDBL_128BIT)
|
||||
static __inline fp_t __compiler_rt_logbl(fp_t x) {
|
||||
return __compiler_rt_logbX(x);
|
||||
}
|
||||
#else
|
||||
// The generic implementation only works for ieee754 floating point. For other
|
||||
// floating point types, continue to rely on the libm implementation for now.
|
||||
static __inline long double __compiler_rt_logbl(long double x) {
|
||||
return crt_logbl(x);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // FP_LIB_HEADER
|
||||
|
|
|
|||
|
|
@ -206,8 +206,8 @@ __gcc_personality_v0(int version, _Unwind_Action actions,
|
|||
if ( lsda == (uint8_t*) 0 )
|
||||
return continueUnwind(exceptionObject, context);
|
||||
|
||||
uintptr_t pc = _Unwind_GetIP(context)-1;
|
||||
uintptr_t funcStart = _Unwind_GetRegionStart(context);
|
||||
uintptr_t pc = (uintptr_t)_Unwind_GetIP(context)-1;
|
||||
uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
|
||||
uintptr_t pcOffset = pc - funcStart;
|
||||
|
||||
/* Parse LSDA header. */
|
||||
|
|
@ -249,4 +249,3 @@ __gcc_personality_v0(int version, _Unwind_Action actions,
|
|||
/* No landing pad found, continue unwinding. */
|
||||
return continueUnwind(exceptionObject, context);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
#define AEABI_RTABI __attribute__((__pcs__("aapcs")))
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define ALWAYS_INLINE __forceinline
|
||||
#define NOINLINE __declspec(noinline)
|
||||
#define NORETURN __declspec(noreturn)
|
||||
|
|
|
|||
|
|
@ -92,12 +92,8 @@
|
|||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define crt_logb(x) logb((x))
|
||||
#define crt_logbf(x) logbf((x))
|
||||
#define crt_logbl(x) logbl((x))
|
||||
#else
|
||||
#define crt_logb(x) __builtin_logb((x))
|
||||
#define crt_logbf(x) __builtin_logbf((x))
|
||||
#define crt_logbl(x) __builtin_logbl((x))
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -60,10 +60,19 @@ typedef union
|
|||
}s;
|
||||
} udwords;
|
||||
|
||||
#if (defined(__LP64__) || defined(__wasm__) || defined(__mips64)) || defined(__riscv)
|
||||
#if defined(__LP64__) || defined(__wasm__) || defined(__mips64) || \
|
||||
defined(__riscv) || defined(_WIN64)
|
||||
#define CRT_HAS_128BIT
|
||||
#endif
|
||||
|
||||
/* MSVC doesn't have a working 128bit integer type. Users should really compile
|
||||
* compiler-rt with clang, but if they happen to be doing a standalone build for
|
||||
* asan or something else, disable the 128 bit parts so things sort of work.
|
||||
*/
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#undef CRT_HAS_128BIT
|
||||
#endif
|
||||
|
||||
#ifdef CRT_HAS_128BIT
|
||||
typedef int ti_int __attribute__ ((mode (TI)));
|
||||
typedef unsigned tu_int __attribute__ ((mode (TI)));
|
||||
|
|
@ -139,6 +148,18 @@ typedef struct
|
|||
#endif /* _YUGA_LITTLE_ENDIAN */
|
||||
} uqwords;
|
||||
|
||||
/* 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__)
|
||||
#define HAS_80_BIT_LONG_DOUBLE 1
|
||||
#else
|
||||
#define HAS_80_BIT_LONG_DOUBLE 0
|
||||
#endif
|
||||
|
||||
#ifndef _STANDALONE
|
||||
typedef union
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ NORETURN extern void panic(const char *, ...);
|
|||
#ifndef _WIN32
|
||||
__attribute__((visibility("hidden")))
|
||||
#endif
|
||||
void compilerrt_abort_impl(const char *file, int line, const char *function) {
|
||||
void __compilerrt_abort_impl(const char *file, int line, const char *function) {
|
||||
panic("%s:%d: abort in %s", file, line, function);
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ NORETURN extern void __assert_rtn(const char *func, const char *file, int line,
|
|||
__attribute__((weak))
|
||||
__attribute__((visibility("hidden")))
|
||||
#endif
|
||||
void compilerrt_abort_impl(const char *file, int line, const char *function) {
|
||||
void __compilerrt_abort_impl(const char *file, int line, const char *function) {
|
||||
__assert_rtn(function, file, line, "libcompiler_rt abort");
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ void compilerrt_abort_impl(const char *file, int line, const char *function) {
|
|||
__attribute__((weak))
|
||||
__attribute__((visibility("hidden")))
|
||||
#endif
|
||||
void compilerrt_abort_impl(const char *file, int line, const char *function) {
|
||||
void __compilerrt_abort_impl(const char *file, int line, const char *function) {
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ void compilerrt_abort_impl(const char *file, int line, const char *function) {
|
|||
__attribute__((weak))
|
||||
__attribute__((visibility("hidden")))
|
||||
#endif
|
||||
void compilerrt_abort_impl(const char *file, int line, const char *function) {
|
||||
void __compilerrt_abort_impl(const char *file, int line, const char *function) {
|
||||
abort();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@
|
|||
#define INT_UTIL_H
|
||||
|
||||
/** \brief Trigger a program abort (or panic for kernel code). */
|
||||
#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, __func__)
|
||||
#define compilerrt_abort() __compilerrt_abort_impl(__FILE__, __LINE__, __func__)
|
||||
|
||||
NORETURN void compilerrt_abort_impl(const char *file, int line,
|
||||
const char *function);
|
||||
NORETURN void __compilerrt_abort_impl(const char *file, int line,
|
||||
const char *function);
|
||||
|
||||
#define COMPILE_TIME_ASSERT(expr) COMPILE_TIME_ASSERT1(expr, __COUNTER__)
|
||||
#define COMPILE_TIME_ASSERT1(expr, cnt) COMPILE_TIME_ASSERT2(expr, cnt)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <TargetConditionals.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <dlfcn.h>
|
||||
|
|
@ -28,6 +27,33 @@
|
|||
static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
|
||||
static dispatch_once_t DispatchOnceCounter;
|
||||
|
||||
/* We can't include <CoreFoundation/CoreFoundation.h> directly from here, so
|
||||
* just forward declare everything that we need from it. */
|
||||
|
||||
typedef const void *CFDataRef, *CFAllocatorRef, *CFPropertyListRef,
|
||||
*CFStringRef, *CFDictionaryRef, *CFTypeRef, *CFErrorRef;
|
||||
|
||||
#if __LLP64__
|
||||
typedef unsigned long long CFTypeID;
|
||||
typedef unsigned long long CFOptionFlags;
|
||||
typedef signed long long CFIndex;
|
||||
#else
|
||||
typedef unsigned long CFTypeID;
|
||||
typedef unsigned long CFOptionFlags;
|
||||
typedef signed long CFIndex;
|
||||
#endif
|
||||
|
||||
typedef unsigned char UInt8;
|
||||
typedef _Bool Boolean;
|
||||
typedef CFIndex CFPropertyListFormat;
|
||||
typedef uint32_t CFStringEncoding;
|
||||
|
||||
/* kCFStringEncodingASCII analog. */
|
||||
#define CF_STRING_ENCODING_ASCII 0x0600
|
||||
/* kCFStringEncodingUTF8 analog. */
|
||||
#define CF_STRING_ENCODING_UTF8 0x08000100
|
||||
#define CF_PROPERTY_LIST_IMMUTABLE 0
|
||||
|
||||
typedef CFDataRef (*CFDataCreateWithBytesNoCopyFuncTy)(CFAllocatorRef,
|
||||
const UInt8 *, CFIndex,
|
||||
CFAllocatorRef);
|
||||
|
|
@ -55,8 +81,7 @@ static void parseSystemVersionPList(void *Unused) {
|
|||
const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
|
||||
if (!NullAllocator)
|
||||
return;
|
||||
const CFAllocatorRef kCFAllocatorNull =
|
||||
*(const CFAllocatorRef *)NullAllocator;
|
||||
const CFAllocatorRef AllocatorNull = *(const CFAllocatorRef *)NullAllocator;
|
||||
CFDataCreateWithBytesNoCopyFuncTy CFDataCreateWithBytesNoCopyFunc =
|
||||
(CFDataCreateWithBytesNoCopyFuncTy)dlsym(RTLD_DEFAULT,
|
||||
"CFDataCreateWithBytesNoCopy");
|
||||
|
|
@ -140,21 +165,21 @@ static void parseSystemVersionPList(void *Unused) {
|
|||
/* Get the file buffer into CF's format. We pass in a null allocator here *
|
||||
* because we free PListBuf ourselves */
|
||||
FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
|
||||
NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull);
|
||||
NULL, PListBuf, (CFIndex)NumRead, AllocatorNull);
|
||||
if (!FileContentsRef)
|
||||
goto Fail;
|
||||
|
||||
if (CFPropertyListCreateWithDataFunc)
|
||||
PListRef = (*CFPropertyListCreateWithDataFunc)(
|
||||
NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL);
|
||||
NULL, FileContentsRef, CF_PROPERTY_LIST_IMMUTABLE, NULL, NULL);
|
||||
else
|
||||
PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
|
||||
NULL, FileContentsRef, kCFPropertyListImmutable, NULL);
|
||||
NULL, FileContentsRef, CF_PROPERTY_LIST_IMMUTABLE, NULL);
|
||||
if (!PListRef)
|
||||
goto Fail;
|
||||
|
||||
CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
|
||||
NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull);
|
||||
NULL, "ProductVersion", CF_STRING_ENCODING_ASCII, AllocatorNull);
|
||||
if (!ProductVersion)
|
||||
goto Fail;
|
||||
CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
|
||||
|
|
@ -165,7 +190,7 @@ static void parseSystemVersionPList(void *Unused) {
|
|||
|
||||
char VersionStr[32];
|
||||
if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
|
||||
sizeof(VersionStr), kCFStringEncodingUTF8))
|
||||
sizeof(VersionStr), CF_STRING_ENCODING_UTF8))
|
||||
goto Fail;
|
||||
sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
|
||||
#include "DD.h"
|
||||
#include "../int_math.h"
|
||||
// Use DOUBLE_PRECISION because the soft-fp method we use is logb (on the upper
|
||||
// half of the long doubles), even though this file defines complex division for
|
||||
// 128-bit floats.
|
||||
#define DOUBLE_PRECISION
|
||||
#include "../fp_lib.h"
|
||||
|
||||
#if !defined(CRT_INFINITY) && defined(HUGE_VAL)
|
||||
#define CRT_INFINITY HUGE_VAL
|
||||
|
|
@ -21,9 +26,10 @@ __divtc3(long double a, long double b, long double c, long double d)
|
|||
DD dDD = { .ld = d };
|
||||
|
||||
int ilogbw = 0;
|
||||
const double logbw = crt_logb(crt_fmax(crt_fabs(cDD.s.hi), crt_fabs(dDD.s.hi) ));
|
||||
|
||||
if (crt_isfinite(logbw))
|
||||
const double logbw = __compiler_rt_logb(
|
||||
crt_fmax(crt_fabs(cDD.s.hi), crt_fabs(dDD.s.hi)));
|
||||
|
||||
if (crt_isfinite(logbw))
|
||||
{
|
||||
ilogbw = (int)logbw;
|
||||
|
||||
|
|
|
|||
106
contrib/compiler-rt/lib/builtins/ppc/fixunstfti.c
Normal file
106
contrib/compiler-rt/lib/builtins/ppc/fixunstfti.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
//===-- lib/builtins/ppc/fixunstfti.c - Convert long double->int128 *-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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements converting the 128bit IBM/PowerPC long double (double-
|
||||
// double) data type to an unsigned 128 bit integer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "../int_math.h"
|
||||
#define BIAS 1023
|
||||
|
||||
/* Convert long double into an unsigned 128-bit integer. */
|
||||
__uint128_t __fixunstfti(long double input) {
|
||||
|
||||
/* If we are trying to convert a NaN, return the NaN bit pattern. */
|
||||
if (crt_isnan(input)) {
|
||||
return ((__uint128_t)0x7FF8000000000000ll) << 64 |
|
||||
(__uint128_t)0x0000000000000000ll;
|
||||
}
|
||||
|
||||
__uint128_t result, hiResult, loResult;
|
||||
int hiExponent, loExponent, shift;
|
||||
/* The long double representation, with the high and low portions of
|
||||
* the long double, and the corresponding bit patterns of each double. */
|
||||
union {
|
||||
long double ld;
|
||||
double d[2]; /* [0] is the high double, [1] is the low double. */
|
||||
unsigned long long ull[2]; /* High and low doubles as 64-bit integers. */
|
||||
} ldUnion;
|
||||
|
||||
/* If the long double is less than 1.0 or negative,
|
||||
* return 0.0. */
|
||||
if (input < 1.0)
|
||||
return 0.0;
|
||||
|
||||
/* Retrieve the 64-bit patterns of high and low doubles.
|
||||
* Compute the unbiased exponent of both high and low doubles by
|
||||
* removing the signs, isolating the exponent, and subtracting
|
||||
* the bias from it. */
|
||||
ldUnion.ld = input;
|
||||
hiExponent = ((ldUnion.ull[0] & 0x7FFFFFFFFFFFFFFFll) >> 52) - BIAS;
|
||||
loExponent = ((ldUnion.ull[1] & 0x7FFFFFFFFFFFFFFFll) >> 52) - BIAS;
|
||||
|
||||
/* Convert each double into int64; they will be added to the int128 result.
|
||||
* CASE 1: High or low double fits in int64
|
||||
* - Convert the each double normally into int64.
|
||||
*
|
||||
* CASE 2: High or low double does not fit in int64
|
||||
* - Scale the double to fit within a 64-bit integer
|
||||
* - Calculate the shift (amount to scale the double by in the int128)
|
||||
* - Clear all the bits of the exponent (with 0x800FFFFFFFFFFFFF)
|
||||
* - Add BIAS+53 (0x4350000000000000) to exponent to correct the value
|
||||
* - Scale (move) the double to the correct place in the int128
|
||||
* (Move it by 2^53 places)
|
||||
*
|
||||
* Note: If the high double is assumed to be positive, an unsigned conversion
|
||||
* from long double to 64-bit integer is needed. The low double can be either
|
||||
* positive or negative, so a signed conversion is needed to retain the result
|
||||
* of the low double and to ensure it does not simply get converted to 0. */
|
||||
|
||||
/* CASE 1 - High double fits in int64. */
|
||||
if (hiExponent < 63) {
|
||||
hiResult = (unsigned long long)ldUnion.d[0];
|
||||
} else if (hiExponent < 128) {
|
||||
/* CASE 2 - High double does not fit in int64, scale and convert it. */
|
||||
shift = hiExponent - 54;
|
||||
ldUnion.ull[0] &= 0x800FFFFFFFFFFFFFll;
|
||||
ldUnion.ull[0] |= 0x4350000000000000ll;
|
||||
hiResult = (unsigned long long)ldUnion.d[0];
|
||||
hiResult <<= shift;
|
||||
} else {
|
||||
/* Detect cases for overflow. When the exponent of the high
|
||||
* double is greater than 128 bits and when the long double
|
||||
* input is positive, return the max 128-bit integer.
|
||||
* For negative inputs with exponents > 128, return 1, like gcc. */
|
||||
if (ldUnion.d[0] > 0) {
|
||||
return ((__uint128_t)0xFFFFFFFFFFFFFFFFll) << 64 |
|
||||
(__uint128_t)0xFFFFFFFFFFFFFFFFll;
|
||||
} else {
|
||||
return ((__uint128_t)0x0000000000000000ll) << 64 |
|
||||
(__uint128_t)0x0000000000000001ll;
|
||||
}
|
||||
}
|
||||
|
||||
/* CASE 1 - Low double fits in int64. */
|
||||
if (loExponent < 63) {
|
||||
loResult = (long long)ldUnion.d[1];
|
||||
} else {
|
||||
/* CASE 2 - Low double does not fit in int64, scale and convert it. */
|
||||
shift = loExponent - 54;
|
||||
ldUnion.ull[1] &= 0x800FFFFFFFFFFFFFll;
|
||||
ldUnion.ull[1] |= 0x4350000000000000ll;
|
||||
loResult = (long long)ldUnion.d[1];
|
||||
loResult <<= shift;
|
||||
}
|
||||
|
||||
/* Add the high and low doublewords together to form a 128 bit integer. */
|
||||
result = loResult + hiResult;
|
||||
return result;
|
||||
}
|
||||
48
contrib/compiler-rt/lib/builtins/ppc/floattitf.c
Normal file
48
contrib/compiler-rt/lib/builtins/ppc/floattitf.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
//===-- lib/builtins/ppc/floattitf.c - Convert int128->long double -*-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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements converting a signed 128 bit integer to a 128bit IBM /
|
||||
// PowerPC long double (double-double) value.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Conversions from signed and unsigned 64-bit int to long double. */
|
||||
long double __floatditf(int64_t);
|
||||
long double __floatunditf(uint64_t);
|
||||
|
||||
/* Convert a signed 128-bit integer to long double.
|
||||
* This uses the following property: Let hi and lo be 64-bits each,
|
||||
* and let signed_val_k() and unsigned_val_k() be the value of the
|
||||
* argument interpreted as a signed or unsigned k-bit integer. Then,
|
||||
*
|
||||
* signed_val_128(hi,lo) = signed_val_64(hi) * 2^64 + unsigned_val_64(lo)
|
||||
* = (long double)hi * 2^64 + (long double)lo,
|
||||
*
|
||||
* where (long double)hi and (long double)lo are signed and
|
||||
* unsigned 64-bit integer to long double conversions, respectively.
|
||||
*/
|
||||
long double __floattitf(__int128_t arg) {
|
||||
/* Split the int128 argument into 64-bit high and low int64 parts. */
|
||||
int64_t ArgHiPart = (int64_t)(arg >> 64);
|
||||
uint64_t ArgLoPart = (uint64_t)arg;
|
||||
|
||||
/* Convert each 64-bit part into long double. The high part
|
||||
* must be a signed conversion and the low part an unsigned conversion
|
||||
* to ensure the correct result. */
|
||||
long double ConvertedHiPart = __floatditf(ArgHiPart);
|
||||
long double ConvertedLoPart = __floatunditf(ArgLoPart);
|
||||
|
||||
/* The low bit of ArgHiPart corresponds to the 2^64 bit in arg.
|
||||
* Multiply the high part by 2^64 to undo the right shift by 64-bits
|
||||
* done in the splitting. Then, add to the low part to obtain the
|
||||
* final result. */
|
||||
return ((ConvertedHiPart * 0x1.0p64) + ConvertedLoPart);
|
||||
}
|
||||
|
|
@ -13,15 +13,33 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#if SANITIZER_FREEBSD
|
||||
#include <sys/link_elf.h>
|
||||
#endif
|
||||
#include <link.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#if SANITIZER_LINUX
|
||||
typedef ElfW(Phdr) Elf_Phdr;
|
||||
typedef ElfW(Ehdr) Elf_Ehdr;
|
||||
typedef ElfW(Addr) Elf_Addr;
|
||||
typedef ElfW(Sym) Elf_Sym;
|
||||
typedef ElfW(Dyn) Elf_Dyn;
|
||||
#elif SANITIZER_FREEBSD
|
||||
#if SANITIZER_WORDSIZE == 64
|
||||
#define ElfW64_Dyn Elf_Dyn
|
||||
#define ElfW64_Sym Elf_Sym
|
||||
#else
|
||||
#define ElfW32_Dyn Elf_Dyn
|
||||
#define ElfW32_Sym Elf_Sym
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
#include "ubsan/ubsan_init.h"
|
||||
#include "ubsan/ubsan_flags.h"
|
||||
|
|
@ -154,15 +172,25 @@ void ShadowBuilder::Add(uptr begin, uptr end, uptr cfi_check) {
|
|||
*s = sv;
|
||||
}
|
||||
|
||||
#if SANITIZER_LINUX
|
||||
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD
|
||||
void ShadowBuilder::Install() {
|
||||
MprotectReadOnly(shadow_, GetShadowSize());
|
||||
uptr main_shadow = GetShadow();
|
||||
if (main_shadow) {
|
||||
// Update.
|
||||
#if SANITIZER_LINUX
|
||||
void *res = mremap((void *)shadow_, GetShadowSize(), GetShadowSize(),
|
||||
MREMAP_MAYMOVE | MREMAP_FIXED, (void *)main_shadow);
|
||||
CHECK(res != MAP_FAILED);
|
||||
#elif SANITIZER_NETBSD
|
||||
void *res = mremap((void *)shadow_, GetShadowSize(), (void *)main_shadow,
|
||||
GetShadowSize(), MAP_FIXED);
|
||||
CHECK(res != MAP_FAILED);
|
||||
#else
|
||||
void *res = MmapFixedOrDie(shadow_, GetShadowSize());
|
||||
CHECK(res != MAP_FAILED);
|
||||
::memcpy(&shadow_, &main_shadow, GetShadowSize());
|
||||
#endif
|
||||
} else {
|
||||
// Initial setup.
|
||||
CHECK_EQ(kCfiShadowLimitsStorageSize, GetPageSizeCached());
|
||||
|
|
@ -183,17 +211,17 @@ void ShadowBuilder::Install() {
|
|||
// dlopen(RTLD_NOLOAD | RTLD_LAZY)
|
||||
// dlsym("__cfi_check").
|
||||
uptr find_cfi_check_in_dso(dl_phdr_info *info) {
|
||||
const ElfW(Dyn) *dynamic = nullptr;
|
||||
const Elf_Dyn *dynamic = nullptr;
|
||||
for (int i = 0; i < info->dlpi_phnum; ++i) {
|
||||
if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
|
||||
dynamic =
|
||||
(const ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
|
||||
(const Elf_Dyn *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dynamic) return 0;
|
||||
uptr strtab = 0, symtab = 0, strsz = 0;
|
||||
for (const ElfW(Dyn) *p = dynamic; p->d_tag != PT_NULL; ++p) {
|
||||
for (const Elf_Dyn *p = dynamic; p->d_tag != PT_NULL; ++p) {
|
||||
if (p->d_tag == DT_SYMTAB)
|
||||
symtab = p->d_un.d_ptr;
|
||||
else if (p->d_tag == DT_STRTAB)
|
||||
|
|
@ -227,7 +255,7 @@ uptr find_cfi_check_in_dso(dl_phdr_info *info) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
for (const ElfW(Sym) *p = (const ElfW(Sym) *)symtab; (ElfW(Addr))p < strtab;
|
||||
for (const Elf_Sym *p = (const Elf_Sym *)symtab; (Elf_Addr)p < strtab;
|
||||
++p) {
|
||||
// There is no reliable way to find the end of the symbol table. In
|
||||
// lld-produces files, there are other sections between symtab and strtab.
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
[cfi-unrelated-cast]
|
||||
# The specification of std::get_temporary_buffer mandates a cast to
|
||||
# uninitialized T* (libstdc++, libc++, MSVC stdlib).
|
||||
# uninitialized T* (libstdc++, MSVC stdlib).
|
||||
fun:_ZSt20get_temporary_buffer*
|
||||
fun:_ZNSt3__120get_temporary_buffer*
|
||||
fun:*get_temporary_buffer@.*@std@@*
|
||||
|
||||
# STL address-of magic (libstdc++, libc++).
|
||||
# STL address-of magic (libstdc++).
|
||||
fun:*__addressof*
|
||||
fun:_ZNSt3__19addressof*
|
||||
|
||||
# Windows C++ stdlib headers that contain bad unrelated casts.
|
||||
src:*xmemory0
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ static void dfsan_fini() {
|
|||
static void dfsan_init(int argc, char **argv, char **envp) {
|
||||
InitializeFlags();
|
||||
|
||||
InitializePlatformEarly();
|
||||
::InitializePlatformEarly();
|
||||
|
||||
if (!MmapFixedNoReserve(ShadowAddr(), UnusedAddr() - ShadowAddr()))
|
||||
Die();
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ INTERCEPTOR(int, rmdir, char *path) {
|
|||
// Signal-related interceptors
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if SANITIZER_LINUX
|
||||
#if SANITIZER_LINUX || SANITIZER_FREEBSD
|
||||
typedef void (*signal_handler_t)(int);
|
||||
INTERCEPTOR(signal_handler_t, signal, int signum, signal_handler_t handler) {
|
||||
void *ctx;
|
||||
|
|
@ -344,7 +344,7 @@ INTERCEPTOR(signal_handler_t, signal, int signum, signal_handler_t handler) {
|
|||
#define ESAN_MAYBE_INTERCEPT_SIGNAL
|
||||
#endif
|
||||
|
||||
#if SANITIZER_LINUX
|
||||
#if SANITIZER_LINUX || SANITIZER_FREEBSD
|
||||
DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact)
|
||||
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
|
||||
|
|
@ -363,7 +363,11 @@ int real_sigaction(int signum, const void *act, void *oldact) {
|
|||
if (REAL(sigaction) == nullptr) {
|
||||
// With an instrumented allocator, this is called during interceptor init
|
||||
// and we need a raw syscall solution.
|
||||
#if SANITIZER_LINUX
|
||||
return internal_sigaction_syscall(signum, act, oldact);
|
||||
#else
|
||||
return internal_sigaction(signum, act, oldact);
|
||||
#endif
|
||||
}
|
||||
return REAL(sigaction)(signum, (const struct sigaction *)act,
|
||||
(struct sigaction *)oldact);
|
||||
|
|
@ -376,7 +380,7 @@ int real_sigaction(int signum, const void *act, void *oldact) {
|
|||
#define ESAN_MAYBE_INTERCEPT_SIGACTION
|
||||
#endif
|
||||
|
||||
#if SANITIZER_LINUX
|
||||
#if SANITIZER_LINUX || SANITIZER_FREEBSD
|
||||
INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
|
||||
__sanitizer_sigset_t *oldset) {
|
||||
void *ctx;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ struct ApplicationRegion {
|
|||
bool ShadowMergedWithPrev;
|
||||
};
|
||||
|
||||
#if SANITIZER_LINUX && defined(__x86_64__)
|
||||
#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && defined(__x86_64__)
|
||||
// Linux x86_64
|
||||
//
|
||||
// Application memory falls into these 5 regions (ignoring the corner case
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include "sanitizer_common/sanitizer_platform_limits_freebsd.h"
|
||||
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
|
||||
|
||||
namespace __esan {
|
||||
|
|
|
|||
35
contrib/compiler-rt/lib/esan/esan_sideline_bsd.cpp
Normal file
35
contrib/compiler-rt/lib/esan/esan_sideline_bsd.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
//===-- esan_sideline_bsd.cpp -----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of EfficiencySanitizer, a family of performance tuners.
|
||||
//
|
||||
// Support for a separate or "sideline" tool thread on FreeBSD.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_FREEBSD
|
||||
|
||||
#include "esan_sideline.h"
|
||||
|
||||
namespace __esan {
|
||||
|
||||
static SidelineThread *TheThread;
|
||||
|
||||
bool SidelineThread::launchThread(SidelineFunc takeSample, void *Arg,
|
||||
u32 FreqMilliSec) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SidelineThread::joinThread() {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace __esan
|
||||
|
||||
#endif // SANITIZER_FREEBSD
|
||||
36
contrib/compiler-rt/lib/fuzzer/FuzzerBuiltins.h
Normal file
36
contrib/compiler-rt/lib/fuzzer/FuzzerBuiltins.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
//===- FuzzerBuiltins.h - Internal header for builtins ----------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Wrapper functions and marcos around builtin functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_BUILTINS_H
|
||||
#define LLVM_FUZZER_BUILTINS_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
#if !LIBFUZZER_MSVC
|
||||
#include <cstdint>
|
||||
|
||||
#define GET_CALLER_PC() __builtin_return_address(0)
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
inline uint8_t Bswap(uint8_t x) { return x; }
|
||||
inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
|
||||
inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
|
||||
inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
|
||||
|
||||
inline uint32_t Clzll(unsigned long long X) { return __builtin_clzll(X); }
|
||||
inline uint32_t Clz(unsigned long long X) { return __builtin_clz(X); }
|
||||
inline int Popcountll(unsigned long long X) { return __builtin_popcountll(X); }
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // !LIBFUZZER_MSVC
|
||||
#endif // LLVM_FUZZER_BUILTINS_H
|
||||
59
contrib/compiler-rt/lib/fuzzer/FuzzerBuiltinsMsvc.h
Normal file
59
contrib/compiler-rt/lib/fuzzer/FuzzerBuiltinsMsvc.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
//===- FuzzerBuiltinsMSVC.h - Internal header for builtins ------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Wrapper functions and marcos that use intrinsics instead of builtin functions
|
||||
// which cannot be compiled by MSVC.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_BUILTINS_MSVC_H
|
||||
#define LLVM_FUZZER_BUILTINS_MSVC_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
#if LIBFUZZER_MSVC
|
||||
#if !defined(_M_ARM) && !defined(_M_X64)
|
||||
#error "_BitScanReverse64 unavailable on this platform so MSVC is unsupported."
|
||||
#endif
|
||||
#include <intrin.h>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
// __builtin_return_address() cannot be compiled with MSVC. Use the equivalent
|
||||
// from <intrin.h>
|
||||
#define GET_CALLER_PC() reinterpret_cast<uintptr_t>(_ReturnAddress())
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
inline uint8_t Bswap(uint8_t x) { return x; }
|
||||
// Use alternatives to __builtin functions from <stdlib.h> and <intrin.h> on
|
||||
// Windows since the builtins are not supported by MSVC.
|
||||
inline uint16_t Bswap(uint16_t x) { return _byteswap_ushort(x); }
|
||||
inline uint32_t Bswap(uint32_t x) { return _byteswap_ulong(x); }
|
||||
inline uint64_t Bswap(uint64_t x) { return _byteswap_uint64(x); }
|
||||
|
||||
// The functions below were mostly copied from
|
||||
// compiler-rt/lib/builtins/int_lib.h which defines the __builtin functions used
|
||||
// outside of Windows.
|
||||
inline uint32_t Clzll(uint64_t X) {
|
||||
unsigned long LeadZeroIdx = 0;
|
||||
if (_BitScanReverse64(&LeadZeroIdx, X)) return 63 - LeadZeroIdx;
|
||||
return 64;
|
||||
}
|
||||
|
||||
inline uint32_t Clz(uint32_t X) {
|
||||
unsigned long LeadZeroIdx = 0;
|
||||
if (_BitScanReverse(&LeadZeroIdx, X)) return 31 - LeadZeroIdx;
|
||||
return 32;
|
||||
}
|
||||
|
||||
inline int Popcountll(unsigned long long X) { return __popcnt64(X); }
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZER_MSVC
|
||||
#endif // LLVM_FUZZER_BUILTINS_MSVC_H
|
||||
|
|
@ -81,7 +81,7 @@ public:
|
|||
}
|
||||
|
||||
// Like hasArgument, but checks for "-[Flag]=...".
|
||||
bool hasFlag(const std::string &Flag) {
|
||||
bool hasFlag(const std::string &Flag) const {
|
||||
std::string Arg("-" + Flag + "=");
|
||||
auto IsMatch = [&](const std::string &Other) {
|
||||
return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
|
||||
|
|
@ -92,7 +92,7 @@ public:
|
|||
// Returns the value of the first instance of a given flag, or an empty string
|
||||
// if the flag isn't present. Ignores any occurrences after
|
||||
// "-ignore_remaining_args=1", if present.
|
||||
std::string getFlagValue(const std::string &Flag) {
|
||||
std::string getFlagValue(const std::string &Flag) const {
|
||||
std::string Arg("-" + Flag + "=");
|
||||
auto IsMatch = [&](const std::string &Other) {
|
||||
return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
|
||||
|
|
|
|||
|
|
@ -238,12 +238,6 @@ class InputCorpus {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool IsFeatureNew(size_t Idx, uint32_t NewSize, bool Shrink) {
|
||||
assert(NewSize);
|
||||
uint32_t OldSize = GetFeature(Idx % kFeatureSetSize);
|
||||
return OldSize == 0 || (Shrink && OldSize > NewSize);
|
||||
}
|
||||
|
||||
size_t NumFeatures() const { return NumAddedFeatures; }
|
||||
size_t NumFeatureUpdates() const { return NumUpdatedFeatures; }
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,13 @@
|
|||
#error "Support for your platform has not been implemented"
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
// MSVC compiler is being used.
|
||||
#define LIBFUZZER_MSVC 1
|
||||
#else
|
||||
#define LIBFUZZER_MSVC 0
|
||||
#endif
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
|
|
@ -129,8 +136,15 @@
|
|||
|
||||
#if LIBFUZZER_WINDOWS
|
||||
#define ATTRIBUTE_INTERFACE __declspec(dllexport)
|
||||
// This is used for __sancov_lowest_stack which is needed for
|
||||
// -fsanitize-coverage=stack-depth. That feature is not yet available on
|
||||
// Windows, so make the symbol static to avoid linking errors.
|
||||
#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \
|
||||
__attribute__((tls_model("initial-exec"))) thread_local static
|
||||
#else
|
||||
#define ATTRIBUTE_INTERFACE __attribute__((visibility("default")))
|
||||
#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \
|
||||
ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) thread_local
|
||||
#endif
|
||||
|
||||
namespace fuzzer {
|
||||
|
|
@ -176,11 +190,6 @@ typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
|
|||
|
||||
int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
|
||||
|
||||
inline uint8_t Bswap(uint8_t x) { return x; }
|
||||
inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
|
||||
inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
|
||||
inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
|
||||
|
||||
uint8_t *ExtraCountersBegin();
|
||||
uint8_t *ExtraCountersEnd();
|
||||
void ClearExtraCounters();
|
||||
|
|
|
|||
|
|
@ -615,13 +615,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
|
|||
Options.PrintNewCovPcs = Flags.print_pcs;
|
||||
Options.PrintNewCovFuncs = Flags.print_funcs;
|
||||
Options.PrintFinalStats = Flags.print_final_stats;
|
||||
Options.PrintMutationStats = Flags.print_mutation_stats;
|
||||
Options.PrintCorpusStats = Flags.print_corpus_stats;
|
||||
Options.PrintCoverage = Flags.print_coverage;
|
||||
Options.PrintUnstableStats = Flags.print_unstable_stats;
|
||||
if (Flags.handle_unstable == TracePC::MinUnstable ||
|
||||
Flags.handle_unstable == TracePC::ZeroUnstable)
|
||||
Options.HandleUnstable = Flags.handle_unstable;
|
||||
Options.DumpCoverage = Flags.dump_coverage;
|
||||
if (Flags.exit_on_src_pos)
|
||||
Options.ExitOnSrcPos = Flags.exit_on_src_pos;
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
//===- FuzzerExtFunctionsDlsymWin.cpp - Interface to external functions ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation using dynamic loading for Windows.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_WINDOWS
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "Windows.h"
|
||||
|
||||
// This must be included after Windows.h.
|
||||
#include "Psapi.h"
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
ExternalFunctions::ExternalFunctions() {
|
||||
HMODULE Modules[1024];
|
||||
DWORD BytesNeeded;
|
||||
HANDLE CurrentProcess = GetCurrentProcess();
|
||||
|
||||
if (!EnumProcessModules(CurrentProcess, Modules, sizeof(Modules),
|
||||
&BytesNeeded)) {
|
||||
Printf("EnumProcessModules failed (error: %d).\n", GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (sizeof(Modules) < BytesNeeded) {
|
||||
Printf("Error: the array is not big enough to hold all loaded modules.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (BytesNeeded / sizeof(HMODULE)); i++)
|
||||
{
|
||||
FARPROC Fn;
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
if (this->NAME == nullptr) { \
|
||||
Fn = GetProcAddress(Modules[i], #NAME); \
|
||||
if (Fn == nullptr) \
|
||||
Fn = GetProcAddress(Modules[i], #NAME "__dll"); \
|
||||
this->NAME = (decltype(ExternalFunctions::NAME)) Fn; \
|
||||
}
|
||||
#include "FuzzerExtFunctions.def"
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
if (this->NAME == nullptr && WARN) \
|
||||
Printf("WARNING: Failed to find function \"%s\".\n", #NAME);
|
||||
#include "FuzzerExtFunctions.def"
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_WINDOWS
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
extern "C" {
|
||||
// Declare these symbols as weak to allow them to be optionally defined.
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
__attribute__((weak)) RETURN_TYPE NAME FUNC_SIG
|
||||
__attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
//===- FuzzerExtFunctionsWeakAlias.cpp - Interface to external functions --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation using weak aliases. Works for Windows.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_WINDOWS
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
|
||||
using namespace fuzzer;
|
||||
|
||||
extern "C" {
|
||||
// Declare these symbols as weak to allow them to be optionally defined.
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
RETURN_TYPE NAME##Def FUNC_SIG { \
|
||||
Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \
|
||||
exit(1); \
|
||||
} \
|
||||
RETURN_TYPE NAME FUNC_SIG __attribute__((weak, alias(#NAME "Def")));
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) {
|
||||
if (Fun == FunDef) {
|
||||
if (WarnIfMissing)
|
||||
Printf("WARNING: Failed to find function \"%s\".\n", FnName);
|
||||
return nullptr;
|
||||
}
|
||||
return Fun;
|
||||
}
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
ExternalFunctions::ExternalFunctions() {
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
this->NAME = GetFnPtr<decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN);
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_WINDOWS
|
||||
83
contrib/compiler-rt/lib/fuzzer/FuzzerExtFunctionsWindows.cpp
Normal file
83
contrib/compiler-rt/lib/fuzzer/FuzzerExtFunctionsWindows.cpp
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
//=== FuzzerExtWindows.cpp - Interface to external functions --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation of FuzzerExtFunctions for Windows. Uses alternatename when
|
||||
// compiled with MSVC. Uses weak aliases when compiled with clang. Unfortunately
|
||||
// the method each compiler supports is not supported by the other.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_WINDOWS
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
|
||||
using namespace fuzzer;
|
||||
|
||||
// Intermediate macro to ensure the parameter is expanded before stringified.
|
||||
#define STRINGIFY_(A) #A
|
||||
#define STRINGIFY(A) STRINGIFY_(A)
|
||||
|
||||
#if LIBFUZZER_MSVC
|
||||
// Copied from compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h
|
||||
#if defined(_M_IX86) || defined(__i386__)
|
||||
#define WIN_SYM_PREFIX "_"
|
||||
#else
|
||||
#define WIN_SYM_PREFIX
|
||||
#endif
|
||||
|
||||
// Declare external functions as having alternativenames, so that we can
|
||||
// determine if they are not defined.
|
||||
#define EXTERNAL_FUNC(Name, Default) \
|
||||
__pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \
|
||||
Name) "=" WIN_SYM_PREFIX STRINGIFY(Default)))
|
||||
#else
|
||||
// Declare external functions as weak to allow them to default to a specified
|
||||
// function if not defined explicitly. We must use weak symbols because clang's
|
||||
// support for alternatename is not 100%, see
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=40218 for more details.
|
||||
#define EXTERNAL_FUNC(Name, Default) \
|
||||
__attribute__((weak, alias(STRINGIFY(Default))))
|
||||
#endif // LIBFUZZER_MSVC
|
||||
|
||||
extern "C" {
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
RETURN_TYPE NAME##Def FUNC_SIG { \
|
||||
Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \
|
||||
exit(1); \
|
||||
} \
|
||||
EXTERNAL_FUNC(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG;
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) {
|
||||
if (Fun == FunDef) {
|
||||
if (WarnIfMissing)
|
||||
Printf("WARNING: Failed to find function \"%s\".\n", FnName);
|
||||
return nullptr;
|
||||
}
|
||||
return Fun;
|
||||
}
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
ExternalFunctions::ExternalFunctions() {
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
this->NAME = GetFnPtr<decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN);
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_WINDOWS
|
||||
|
|
@ -17,7 +17,7 @@ FUZZER_FLAG_INT(runs, -1,
|
|||
FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. "
|
||||
"If 0, libFuzzer tries to guess a good value based on the corpus "
|
||||
"and reports it. ")
|
||||
FUZZER_FLAG_INT(len_control, 1000, "Try generating small inputs first, "
|
||||
FUZZER_FLAG_INT(len_control, 100, "Try generating small inputs first, "
|
||||
"then try larger inputs over time. Specifies the rate at which the length "
|
||||
"limit is increased (smaller == faster). If 0, immediately try inputs with "
|
||||
"size up to max_len.")
|
||||
|
|
@ -110,15 +110,6 @@ FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text"
|
|||
FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated."
|
||||
" If 1, dump coverage information as a"
|
||||
" .sancov file at exit.")
|
||||
FUZZER_FLAG_INT(handle_unstable, 0, "Experimental."
|
||||
" Executes every input 3 times in total if a unique feature"
|
||||
" is found during the first execution."
|
||||
" If 1, we only use the minimum hit count from the 3 runs"
|
||||
" to determine whether an input is interesting."
|
||||
" If 2, we disregard edges that are found unstable for"
|
||||
" feature collection.")
|
||||
FUZZER_FLAG_INT(print_unstable_stats, 0, "Experimental."
|
||||
" If 1, print unstable statistics at exit.")
|
||||
FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
|
||||
FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.")
|
||||
FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.")
|
||||
|
|
@ -162,4 +153,3 @@ FUZZER_DEPRECATED_FLAG(use_equivalence_server)
|
|||
FUZZER_FLAG_INT(analyze_dict, 0, "Experimental")
|
||||
FUZZER_DEPRECATED_FLAG(use_clang_coverage)
|
||||
FUZZER_FLAG_STRING(data_flow_trace, "Experimental: use the data flow trace")
|
||||
FUZZER_FLAG_INT(print_mutation_stats, 0, "Experimental")
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ long GetEpoch(const std::string &Path) {
|
|||
}
|
||||
|
||||
Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
|
||||
std::ifstream T(Path);
|
||||
std::ifstream T(Path, std::ios::binary);
|
||||
if (ExitOnError && !T) {
|
||||
Printf("No such directory: %s; exiting\n", Path.c_str());
|
||||
exit(1);
|
||||
|
|
@ -51,7 +51,7 @@ Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
|
|||
}
|
||||
|
||||
std::string FileToString(const std::string &Path) {
|
||||
std::ifstream T(Path);
|
||||
std::ifstream T(Path, std::ios::binary);
|
||||
return std::string((std::istreambuf_iterator<char>(T)),
|
||||
std::istreambuf_iterator<char>());
|
||||
}
|
||||
|
|
@ -100,14 +100,6 @@ std::string DirPlusFile(const std::string &DirPath,
|
|||
return DirPath + GetSeparator() + FileName;
|
||||
}
|
||||
|
||||
std::string Basename(const std::string &Path, char Separator) {
|
||||
size_t Pos = Path.rfind(Separator);
|
||||
if (Pos == std::string::npos)
|
||||
return Path;
|
||||
assert(Pos < Path.size());
|
||||
return Path.substr(Pos + 1);
|
||||
}
|
||||
|
||||
void DupAndCloseStderr() {
|
||||
int OutputFd = DuplicateFile(2);
|
||||
if (OutputFd > 0) {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);
|
|||
|
||||
char GetSeparator();
|
||||
// Similar to the basename utility: returns the file name w/o the dir prefix.
|
||||
std::string Basename(const std::string &Path, char Separator = GetSeparator());
|
||||
std::string Basename(const std::string &Path);
|
||||
|
||||
FILE* OpenFile(int Fd, const char *Mode);
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,13 @@ size_t FileSize(const std::string &Path) {
|
|||
return St.st_size;
|
||||
}
|
||||
|
||||
std::string Basename(const std::string &Path) {
|
||||
size_t Pos = Path.rfind(GetSeparator());
|
||||
if (Pos == std::string::npos) return Path;
|
||||
assert(Pos < Path.size());
|
||||
return Path.substr(Pos + 1);
|
||||
}
|
||||
|
||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||
Vector<std::string> *V, bool TopDir) {
|
||||
auto E = GetEpoch(Dir);
|
||||
|
|
|
|||
|
|
@ -72,6 +72,26 @@ bool IsFile(const std::string &Path) {
|
|||
return IsFile(Path, Att);
|
||||
}
|
||||
|
||||
std::string Basename(const std::string &Path) {
|
||||
size_t Pos = Path.find_last_of("/\\");
|
||||
if (Pos == std::string::npos) return Path;
|
||||
assert(Pos < Path.size());
|
||||
return Path.substr(Pos + 1);
|
||||
}
|
||||
|
||||
size_t FileSize(const std::string &Path) {
|
||||
WIN32_FILE_ATTRIBUTE_DATA attr;
|
||||
if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) {
|
||||
Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
|
||||
Path.c_str(), GetLastError());
|
||||
return 0;
|
||||
}
|
||||
ULARGE_INTEGER size;
|
||||
size.HighPart = attr.nFileSizeHigh;
|
||||
size.LowPart = attr.nFileSizeLow;
|
||||
return size.QuadPart;
|
||||
}
|
||||
|
||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||
Vector<std::string> *V, bool TopDir) {
|
||||
auto E = GetEpoch(Dir);
|
||||
|
|
@ -91,7 +111,7 @@ void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
|||
{
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND)
|
||||
return;
|
||||
Printf("No such directory: %s; exiting\n", Dir.c_str());
|
||||
Printf("No such file or directory: %s; exiting\n", Dir.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ public:
|
|||
static void StaticGracefulExitCallback();
|
||||
|
||||
void ExecuteCallback(const uint8_t *Data, size_t Size);
|
||||
void CheckForUnstableCounters(const uint8_t *Data, size_t Size);
|
||||
bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false,
|
||||
InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr);
|
||||
|
||||
|
|
|
|||
|
|
@ -275,7 +275,8 @@ NO_SANITIZE_MEMORY
|
|||
void Fuzzer::AlarmCallback() {
|
||||
assert(Options.UnitTimeoutSec > 0);
|
||||
// In Windows Alarm callback is executed by a different thread.
|
||||
#if !LIBFUZZER_WINDOWS
|
||||
// NetBSD's current behavior needs this change too.
|
||||
#if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD
|
||||
if (!InFuzzingThread())
|
||||
return;
|
||||
#endif
|
||||
|
|
@ -354,13 +355,10 @@ void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {
|
|||
void Fuzzer::PrintFinalStats() {
|
||||
if (Options.PrintCoverage)
|
||||
TPC.PrintCoverage();
|
||||
if (Options.PrintUnstableStats)
|
||||
TPC.PrintUnstableStats();
|
||||
if (Options.DumpCoverage)
|
||||
TPC.DumpCoverage();
|
||||
if (Options.PrintCorpusStats)
|
||||
Corpus.PrintStats();
|
||||
if (Options.PrintMutationStats) MD.PrintMutationStats();
|
||||
if (!Options.PrintFinalStats)
|
||||
return;
|
||||
size_t ExecPerSec = execPerSec();
|
||||
|
|
@ -449,34 +447,6 @@ void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {
|
|||
}
|
||||
}
|
||||
|
||||
void Fuzzer::CheckForUnstableCounters(const uint8_t *Data, size_t Size) {
|
||||
auto CBSetupAndRun = [&]() {
|
||||
ScopedEnableMsanInterceptorChecks S;
|
||||
UnitStartTime = system_clock::now();
|
||||
TPC.ResetMaps();
|
||||
RunningUserCallback = true;
|
||||
CB(Data, Size);
|
||||
RunningUserCallback = false;
|
||||
UnitStopTime = system_clock::now();
|
||||
};
|
||||
|
||||
// Copy original run counters into our unstable counters
|
||||
TPC.InitializeUnstableCounters();
|
||||
|
||||
// First Rerun
|
||||
CBSetupAndRun();
|
||||
TPC.UpdateUnstableCounters(Options.HandleUnstable);
|
||||
|
||||
// Second Rerun
|
||||
CBSetupAndRun();
|
||||
TPC.UpdateUnstableCounters(Options.HandleUnstable);
|
||||
|
||||
// Move minimum hit counts back to ModuleInline8bitCounters
|
||||
if (Options.HandleUnstable == TracePC::MinUnstable ||
|
||||
Options.HandleUnstable == TracePC::ZeroUnstable)
|
||||
TPC.ApplyUnstableCounters();
|
||||
}
|
||||
|
||||
bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
|
||||
InputInfo *II, bool *FoundUniqFeatures) {
|
||||
if (!Size)
|
||||
|
|
@ -487,17 +457,6 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
|
|||
UniqFeatureSetTmp.clear();
|
||||
size_t FoundUniqFeaturesOfII = 0;
|
||||
size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
|
||||
bool NewFeaturesUnstable = false;
|
||||
|
||||
if (Options.HandleUnstable || Options.PrintUnstableStats) {
|
||||
TPC.CollectFeatures([&](size_t Feature) {
|
||||
if (Corpus.IsFeatureNew(Feature, Size, Options.Shrink))
|
||||
NewFeaturesUnstable = true;
|
||||
});
|
||||
if (NewFeaturesUnstable)
|
||||
CheckForUnstableCounters(Data, Size);
|
||||
}
|
||||
|
||||
TPC.CollectFeatures([&](size_t Feature) {
|
||||
if (Corpus.AddFeature(Feature, Size, Options.Shrink))
|
||||
UniqFeatureSetTmp.push_back(Feature);
|
||||
|
|
@ -506,12 +465,10 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
|
|||
II->UniqFeatureSet.end(), Feature))
|
||||
FoundUniqFeaturesOfII++;
|
||||
});
|
||||
|
||||
if (FoundUniqFeatures)
|
||||
*FoundUniqFeatures = FoundUniqFeaturesOfII;
|
||||
PrintPulseAndReportSlowInput(Data, Size);
|
||||
size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
|
||||
|
||||
if (NumNewFeatures) {
|
||||
TPC.UpdateObservedPCs();
|
||||
Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
|
||||
|
|
|
|||
|
|
@ -30,36 +30,34 @@ MutationDispatcher::MutationDispatcher(Random &Rand,
|
|||
DefaultMutators.insert(
|
||||
DefaultMutators.begin(),
|
||||
{
|
||||
{&MutationDispatcher::Mutate_EraseBytes, "EraseBytes", 0, 0},
|
||||
{&MutationDispatcher::Mutate_InsertByte, "InsertByte", 0, 0},
|
||||
{&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"},
|
||||
{&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
|
||||
{&MutationDispatcher::Mutate_InsertRepeatedBytes,
|
||||
"InsertRepeatedBytes", 0, 0},
|
||||
{&MutationDispatcher::Mutate_ChangeByte, "ChangeByte", 0, 0},
|
||||
{&MutationDispatcher::Mutate_ChangeBit, "ChangeBit", 0, 0},
|
||||
{&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes", 0, 0},
|
||||
{&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt", 0,
|
||||
0},
|
||||
{&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt", 0,
|
||||
0},
|
||||
{&MutationDispatcher::Mutate_CopyPart, "CopyPart", 0, 0},
|
||||
{&MutationDispatcher::Mutate_CrossOver, "CrossOver", 0, 0},
|
||||
"InsertRepeatedBytes"},
|
||||
{&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
|
||||
{&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
|
||||
{&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
|
||||
{&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
|
||||
{&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"},
|
||||
{&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
|
||||
{&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
|
||||
{&MutationDispatcher::Mutate_AddWordFromManualDictionary,
|
||||
"ManualDict", 0, 0},
|
||||
"ManualDict"},
|
||||
{&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
|
||||
"PersAutoDict", 0, 0},
|
||||
"PersAutoDict"},
|
||||
});
|
||||
if(Options.UseCmp)
|
||||
DefaultMutators.push_back(
|
||||
{&MutationDispatcher::Mutate_AddWordFromTORC, "CMP", 0, 0});
|
||||
{&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
|
||||
|
||||
if (EF->LLVMFuzzerCustomMutator)
|
||||
Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom", 0, 0});
|
||||
Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
|
||||
else
|
||||
Mutators = DefaultMutators;
|
||||
|
||||
if (EF->LLVMFuzzerCustomCrossOver)
|
||||
Mutators.push_back(
|
||||
{&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver", 0, 0});
|
||||
{&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
|
||||
}
|
||||
|
||||
static char RandCh(Random &Rand) {
|
||||
|
|
@ -466,7 +464,6 @@ void MutationDispatcher::RecordSuccessfulMutationSequence() {
|
|||
if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
|
||||
PersistentAutoDictionary.push_back({DE->GetW(), 1});
|
||||
}
|
||||
RecordUsefulMutations();
|
||||
}
|
||||
|
||||
void MutationDispatcher::PrintRecommendedDictionary() {
|
||||
|
|
@ -487,7 +484,8 @@ void MutationDispatcher::PrintRecommendedDictionary() {
|
|||
|
||||
void MutationDispatcher::PrintMutationSequence() {
|
||||
Printf("MS: %zd ", CurrentMutatorSequence.size());
|
||||
for (auto M : CurrentMutatorSequence) Printf("%s-", M->Name);
|
||||
for (auto M : CurrentMutatorSequence)
|
||||
Printf("%s-", M.Name);
|
||||
if (!CurrentDictionaryEntrySequence.empty()) {
|
||||
Printf(" DE: ");
|
||||
for (auto DE : CurrentDictionaryEntrySequence) {
|
||||
|
|
@ -515,13 +513,12 @@ size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
|
|||
// in which case they will return 0.
|
||||
// Try several times before returning un-mutated data.
|
||||
for (int Iter = 0; Iter < 100; Iter++) {
|
||||
auto M = &Mutators[Rand(Mutators.size())];
|
||||
size_t NewSize = (this->*(M->Fn))(Data, Size, MaxSize);
|
||||
auto M = Mutators[Rand(Mutators.size())];
|
||||
size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
|
||||
if (NewSize && NewSize <= MaxSize) {
|
||||
if (Options.OnlyASCII)
|
||||
ToASCII(Data, NewSize);
|
||||
CurrentMutatorSequence.push_back(M);
|
||||
M->TotalCount++;
|
||||
return NewSize;
|
||||
}
|
||||
}
|
||||
|
|
@ -562,21 +559,4 @@ void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
|
|||
{W, std::numeric_limits<size_t>::max()});
|
||||
}
|
||||
|
||||
void MutationDispatcher::RecordUsefulMutations() {
|
||||
for (auto M : CurrentMutatorSequence) M->UsefulCount++;
|
||||
}
|
||||
|
||||
void MutationDispatcher::PrintMutationStats() {
|
||||
Printf("\nstat::mutation_usefulness: ");
|
||||
for (size_t i = 0; i < Mutators.size(); i++) {
|
||||
double UsefulPercentage =
|
||||
Mutators[i].TotalCount
|
||||
? (100.0 * Mutators[i].UsefulCount) / Mutators[i].TotalCount
|
||||
: 0;
|
||||
Printf("%.3f", UsefulPercentage);
|
||||
if (i < Mutators.size() - 1) Printf(",");
|
||||
}
|
||||
Printf("\n");
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
|
|
|||
|
|
@ -93,16 +93,10 @@ public:
|
|||
|
||||
Random &GetRand() { return Rand; }
|
||||
|
||||
void PrintMutationStats();
|
||||
|
||||
void RecordUsefulMutations();
|
||||
|
||||
private:
|
||||
struct Mutator {
|
||||
size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
|
||||
const char *Name;
|
||||
uint64_t UsefulCount;
|
||||
uint64_t TotalCount;
|
||||
};
|
||||
|
||||
size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
|
||||
|
|
@ -141,7 +135,6 @@ public:
|
|||
Dictionary PersistentAutoDictionary;
|
||||
|
||||
Vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
|
||||
Vector<Mutator *> CurrentMutatorSequence;
|
||||
|
||||
static const size_t kCmpDictionaryEntriesDequeSize = 16;
|
||||
DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
|
||||
|
|
@ -156,6 +149,7 @@ public:
|
|||
|
||||
Vector<Mutator> Mutators;
|
||||
Vector<Mutator> DefaultMutators;
|
||||
Vector<Mutator> CurrentMutatorSequence;
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
|
|
|||
|
|
@ -52,11 +52,8 @@ struct FuzzingOptions {
|
|||
bool PrintNewCovPcs = false;
|
||||
int PrintNewCovFuncs = 0;
|
||||
bool PrintFinalStats = false;
|
||||
bool PrintMutationStats = false;
|
||||
bool PrintCorpusStats = false;
|
||||
bool PrintCoverage = false;
|
||||
bool PrintUnstableStats = false;
|
||||
int HandleUnstable = 0;
|
||||
bool DumpCoverage = false;
|
||||
bool DetectLeaks = true;
|
||||
int PurgeAllocatorIntervalSec = 1;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerTracePC.h"
|
||||
#include "FuzzerBuiltins.h"
|
||||
#include "FuzzerBuiltinsMsvc.h"
|
||||
#include "FuzzerCorpus.h"
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerDictionary.h"
|
||||
|
|
@ -32,8 +34,7 @@ ATTRIBUTE_INTERFACE
|
|||
uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs];
|
||||
|
||||
// Used by -fsanitize-coverage=stack-depth to track stack depth
|
||||
ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec")))
|
||||
thread_local uintptr_t __sancov_lowest_stack;
|
||||
ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC uintptr_t __sancov_lowest_stack;
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
|
|
@ -57,49 +58,6 @@ size_t TracePC::GetTotalPCCoverage() {
|
|||
return Res;
|
||||
}
|
||||
|
||||
template<class CallBack>
|
||||
void TracePC::IterateInline8bitCounters(CallBack CB) const {
|
||||
if (NumInline8bitCounters && NumInline8bitCounters == NumPCsInPCTables) {
|
||||
size_t CounterIdx = 0;
|
||||
for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
|
||||
uint8_t *Beg = ModuleCounters[i].Start;
|
||||
size_t Size = ModuleCounters[i].Stop - Beg;
|
||||
assert(Size == (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
|
||||
for (size_t j = 0; j < Size; j++, CounterIdx++)
|
||||
CB(i, j, CounterIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes unstable counters by copying Inline8bitCounters to unstable
|
||||
// counters.
|
||||
void TracePC::InitializeUnstableCounters() {
|
||||
IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
|
||||
UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j];
|
||||
});
|
||||
}
|
||||
|
||||
// Compares the current counters with counters from previous runs
|
||||
// and records differences as unstable edges.
|
||||
void TracePC::UpdateUnstableCounters(int UnstableMode) {
|
||||
IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
|
||||
if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter) {
|
||||
UnstableCounters[UnstableIdx].IsUnstable = true;
|
||||
if (UnstableMode == ZeroUnstable)
|
||||
UnstableCounters[UnstableIdx].Counter = 0;
|
||||
else if (UnstableMode == MinUnstable)
|
||||
UnstableCounters[UnstableIdx].Counter = std::min(
|
||||
ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Moves the minimum hit counts to ModuleCounters.
|
||||
void TracePC::ApplyUnstableCounters() {
|
||||
IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
|
||||
ModuleCounters[i].Start[j] = UnstableCounters[UnstableIdx].Counter;
|
||||
});
|
||||
}
|
||||
|
||||
void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
|
||||
if (Start == Stop) return;
|
||||
|
|
@ -185,11 +143,42 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
|
|||
ValueProfileMap.AddValueModPrime(Idx);
|
||||
}
|
||||
|
||||
/// \return the address of the previous instruction.
|
||||
/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.h`
|
||||
inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
|
||||
#if defined(__arm__)
|
||||
// T32 (Thumb) branch instructions might be 16 or 32 bit long,
|
||||
// so we return (pc-2) in that case in order to be safe.
|
||||
// For A32 mode we return (pc-4) because all instructions are 32 bit long.
|
||||
return (PC - 3) & (~1);
|
||||
#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__aarch64__)
|
||||
// PCs are always 4 byte aligned.
|
||||
return PC - 4;
|
||||
#elif defined(__sparc__) || defined(__mips__)
|
||||
return PC - 8;
|
||||
#else
|
||||
return PC - 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// \return the address of the next instruction.
|
||||
/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.cc`
|
||||
inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) {
|
||||
#if defined(__mips__)
|
||||
return PC + 8;
|
||||
#elif defined(__powerpc__) || defined(__sparc__) || defined(__arm__) || \
|
||||
defined(__aarch64__)
|
||||
return PC + 4;
|
||||
#else
|
||||
return PC + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TracePC::UpdateObservedPCs() {
|
||||
Vector<uintptr_t> CoveredFuncs;
|
||||
auto ObservePC = [&](uintptr_t PC) {
|
||||
if (ObservedPCs.insert(PC).second && DoPrintNewPCs) {
|
||||
PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", PC + 1);
|
||||
PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", GetNextInstructionPc(PC));
|
||||
Printf("\n");
|
||||
}
|
||||
};
|
||||
|
|
@ -203,10 +192,15 @@ void TracePC::UpdateObservedPCs() {
|
|||
|
||||
if (NumPCsInPCTables) {
|
||||
if (NumInline8bitCounters == NumPCsInPCTables) {
|
||||
IterateInline8bitCounters([&](int i, int j, int CounterIdx) {
|
||||
if (ModuleCounters[i].Start[j])
|
||||
Observe(ModulePCTable[i].Start[j]);
|
||||
});
|
||||
for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
|
||||
uint8_t *Beg = ModuleCounters[i].Start;
|
||||
size_t Size = ModuleCounters[i].Stop - Beg;
|
||||
assert(Size ==
|
||||
(size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
|
||||
for (size_t j = 0; j < Size; j++)
|
||||
if (Beg[j])
|
||||
Observe(ModulePCTable[i].Start[j]);
|
||||
}
|
||||
} else if (NumGuards == NumPCsInPCTables) {
|
||||
size_t GuardIdx = 1;
|
||||
for (size_t i = 0; i < NumModules; i++) {
|
||||
|
|
@ -224,22 +218,11 @@ void TracePC::UpdateObservedPCs() {
|
|||
for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N;
|
||||
i++) {
|
||||
Printf("\tNEW_FUNC[%zd/%zd]: ", i + 1, CoveredFuncs.size());
|
||||
PrintPC("%p %F %L", "%p", CoveredFuncs[i] + 1);
|
||||
PrintPC("%p %F %L", "%p", GetNextInstructionPc(CoveredFuncs[i]));
|
||||
Printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
|
||||
// TODO: this implementation is x86 only.
|
||||
// see sanitizer_common GetPreviousInstructionPc for full implementation.
|
||||
return PC - 1;
|
||||
}
|
||||
|
||||
inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) {
|
||||
// TODO: this implementation is x86 only.
|
||||
// see sanitizer_common GetPreviousInstructionPc for full implementation.
|
||||
return PC + 1;
|
||||
}
|
||||
|
||||
static std::string GetModuleName(uintptr_t PC) {
|
||||
char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++?
|
||||
|
|
@ -349,15 +332,6 @@ void TracePC::DumpCoverage() {
|
|||
}
|
||||
}
|
||||
|
||||
void TracePC::PrintUnstableStats() {
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < NumInline8bitCounters; i++)
|
||||
if (UnstableCounters[i].IsUnstable)
|
||||
count++;
|
||||
Printf("stat::stability_rate: %.2f\n",
|
||||
100 - static_cast<float>(count * 100) / NumInline8bitCounters);
|
||||
}
|
||||
|
||||
// Value profile.
|
||||
// We keep track of various values that affect control flow.
|
||||
// These values are inserted into a bit-set-based hash map.
|
||||
|
|
@ -401,20 +375,14 @@ ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
|
||||
uint64_t ArgXor = Arg1 ^ Arg2;
|
||||
uint64_t ArgDistance = __builtin_popcountll(ArgXor) + 1; // [1,65]
|
||||
uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance;
|
||||
if (sizeof(T) == 4)
|
||||
TORC4.Insert(ArgXor, Arg1, Arg2);
|
||||
else if (sizeof(T) == 8)
|
||||
TORC8.Insert(ArgXor, Arg1, Arg2);
|
||||
// TODO: remove these flags and instead use all metrics at once.
|
||||
if (UseValueProfileMask & 1)
|
||||
ValueProfileMap.AddValue(Idx);
|
||||
if (UseValueProfileMask & 2)
|
||||
ValueProfileMap.AddValue(
|
||||
PC * 64 + (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1));
|
||||
if (UseValueProfileMask & 4) // alternative way to use the hamming distance
|
||||
ValueProfileMap.AddValue(PC * 64 + ArgDistance);
|
||||
uint64_t HammingDistance = Popcountll(ArgXor); // [0,64]
|
||||
uint64_t AbsoluteDistance = (Arg1 == Arg2 ? 0 : Clzll(Arg1 - Arg2) + 1);
|
||||
ValueProfileMap.AddValue(PC * 128 + HammingDistance);
|
||||
ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance);
|
||||
}
|
||||
|
||||
static size_t InternalStrnlen(const char *S, size_t MaxLen) {
|
||||
|
|
@ -455,7 +423,7 @@ extern "C" {
|
|||
ATTRIBUTE_INTERFACE
|
||||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
uint32_t Idx = *Guard;
|
||||
__sancov_trace_pc_pcs[Idx] = PC;
|
||||
__sancov_trace_pc_guard_8bit_counters[Idx]++;
|
||||
|
|
@ -466,7 +434,7 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
|
|||
ATTRIBUTE_INTERFACE
|
||||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
void __sanitizer_cov_trace_pc() {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
uintptr_t Idx = PC & (((uintptr_t)1 << fuzzer::TracePC::kTracePcBits) - 1);
|
||||
__sancov_trace_pc_pcs[Idx] = PC;
|
||||
__sancov_trace_pc_guard_8bit_counters[Idx]++;
|
||||
|
|
@ -491,7 +459,7 @@ void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
|
|||
ATTRIBUTE_INTERFACE
|
||||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCallerCallee(PC, Callee);
|
||||
}
|
||||
|
||||
|
|
@ -499,7 +467,7 @@ ATTRIBUTE_INTERFACE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
|
||||
}
|
||||
|
||||
|
|
@ -510,7 +478,7 @@ ATTRIBUTE_TARGET_POPCNT
|
|||
// the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however,
|
||||
// should be changed later to make full use of instrumentation.
|
||||
void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
|
||||
}
|
||||
|
||||
|
|
@ -518,7 +486,7 @@ ATTRIBUTE_INTERFACE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
|
||||
}
|
||||
|
||||
|
|
@ -526,7 +494,7 @@ ATTRIBUTE_INTERFACE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
|
||||
}
|
||||
|
||||
|
|
@ -534,7 +502,7 @@ ATTRIBUTE_INTERFACE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
|
||||
}
|
||||
|
||||
|
|
@ -542,7 +510,7 @@ ATTRIBUTE_INTERFACE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
|
||||
}
|
||||
|
||||
|
|
@ -550,7 +518,7 @@ ATTRIBUTE_INTERFACE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
|
||||
}
|
||||
|
||||
|
|
@ -558,7 +526,7 @@ ATTRIBUTE_INTERFACE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
|
||||
}
|
||||
|
||||
|
|
@ -572,7 +540,7 @@ void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
|
|||
// Skip the most common and the most boring case.
|
||||
if (Vals[N - 1] < 256 && Val < 256)
|
||||
return;
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
size_t i;
|
||||
uint64_t Token = 0;
|
||||
for (i = 0; i < N; i++) {
|
||||
|
|
@ -593,7 +561,7 @@ ATTRIBUTE_INTERFACE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
void __sanitizer_cov_trace_div4(uint32_t Val) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0);
|
||||
}
|
||||
|
||||
|
|
@ -601,7 +569,7 @@ ATTRIBUTE_INTERFACE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
void __sanitizer_cov_trace_div8(uint64_t Val) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0);
|
||||
}
|
||||
|
||||
|
|
@ -609,7 +577,7 @@ ATTRIBUTE_INTERFACE
|
|||
ATTRIBUTE_NO_SANITIZE_ALL
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
void __sanitizer_cov_trace_gep(uintptr_t Idx) {
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
|
||||
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
|
||||
fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,11 +74,6 @@ class TracePC {
|
|||
// How many bits of PC are used from __sanitizer_cov_trace_pc.
|
||||
static const size_t kTracePcBits = 18;
|
||||
|
||||
enum HandleUnstableOptions {
|
||||
MinUnstable = 1,
|
||||
ZeroUnstable = 2,
|
||||
};
|
||||
|
||||
void HandleInit(uint32_t *Start, uint32_t *Stop);
|
||||
void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop);
|
||||
void HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop);
|
||||
|
|
@ -109,7 +104,6 @@ class TracePC {
|
|||
|
||||
void PrintCoverage();
|
||||
void DumpCoverage();
|
||||
void PrintUnstableStats();
|
||||
|
||||
template<class CallBack>
|
||||
void IterateCoveredFunctions(CallBack CB);
|
||||
|
|
@ -142,18 +136,7 @@ class TracePC {
|
|||
void SetFocusFunction(const std::string &FuncName);
|
||||
bool ObservedFocusFunction();
|
||||
|
||||
void InitializeUnstableCounters();
|
||||
void UpdateUnstableCounters(int UnstableMode);
|
||||
void ApplyUnstableCounters();
|
||||
|
||||
private:
|
||||
struct UnstableEdge {
|
||||
uint8_t Counter;
|
||||
bool IsUnstable;
|
||||
};
|
||||
|
||||
UnstableEdge UnstableCounters[kNumPCs];
|
||||
|
||||
bool UseCounters = false;
|
||||
uint32_t UseValueProfileMask = false;
|
||||
bool DoPrintNewPCs = false;
|
||||
|
|
@ -185,9 +168,6 @@ private:
|
|||
Set<uintptr_t> ObservedPCs;
|
||||
std::unordered_map<uintptr_t, uintptr_t> ObservedFuncs; // PC => Counter.
|
||||
|
||||
template <class Callback>
|
||||
void IterateInline8bitCounters(Callback CB) const;
|
||||
|
||||
std::pair<size_t, size_t> FocusFunction = {-1, -1}; // Module and PC IDs.
|
||||
|
||||
ValueBitMap ValueProfileMap;
|
||||
|
|
|
|||
|
|
@ -12,8 +12,10 @@
|
|||
#ifndef LLVM_FUZZER_UTIL_H
|
||||
#define LLVM_FUZZER_UTIL_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerBuiltins.h"
|
||||
#include "FuzzerBuiltinsMsvc.h"
|
||||
#include "FuzzerCommand.h"
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
|
|
@ -84,7 +86,7 @@ std::string SearchRegexCmd(const std::string &Regex);
|
|||
|
||||
size_t SimpleFastHash(const uint8_t *Data, size_t Size);
|
||||
|
||||
inline uint32_t Log(uint32_t X) { return 32 - __builtin_clz(X) - 1; }
|
||||
inline uint32_t Log(uint32_t X) { return 32 - Clz(X) - 1; }
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
|
|
|
|||
|
|
@ -49,9 +49,6 @@ void CrashTrampolineAsm() __asm__("CrashTrampolineAsm");
|
|||
|
||||
namespace {
|
||||
|
||||
// TODO(phosek): remove this and replace it with ZX_TIME_INFINITE
|
||||
#define ZX_TIME_INFINITE_OLD INT64_MAX
|
||||
|
||||
// A magic value for the Zircon exception port, chosen to spell 'FUZZING'
|
||||
// when interpreted as a byte sequence on little-endian platforms.
|
||||
const uint64_t kFuzzingCrash = 0x474e495a5a5546;
|
||||
|
|
@ -237,7 +234,7 @@ void CrashHandler(zx_handle_t *Event) {
|
|||
"_zx_object_signal");
|
||||
|
||||
zx_port_packet_t Packet;
|
||||
ExitOnErr(_zx_port_wait(Port.Handle, ZX_TIME_INFINITE_OLD, &Packet),
|
||||
ExitOnErr(_zx_port_wait(Port.Handle, ZX_TIME_INFINITE, &Packet),
|
||||
"_zx_port_wait");
|
||||
|
||||
// At this point, we want to get the state of the crashing thread, but
|
||||
|
|
@ -315,8 +312,8 @@ void SetSignalHandler(const FuzzingOptions &Options) {
|
|||
ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create");
|
||||
|
||||
std::thread T(CrashHandler, &Event);
|
||||
zx_status_t Status = _zx_object_wait_one(Event, ZX_USER_SIGNAL_0,
|
||||
ZX_TIME_INFINITE_OLD, nullptr);
|
||||
zx_status_t Status =
|
||||
_zx_object_wait_one(Event, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, nullptr);
|
||||
_zx_handle_close(Event);
|
||||
ExitOnErr(Status, "_zx_object_wait_one");
|
||||
|
||||
|
|
@ -378,19 +375,28 @@ int ExecuteCommand(const Command &Cmd) {
|
|||
Argv[i] = Args[i].c_str();
|
||||
Argv[Argc] = nullptr;
|
||||
|
||||
// Determine stdout
|
||||
// Determine output. On Fuchsia, the fuzzer is typically run as a component
|
||||
// that lacks a mutable working directory. Fortunately, when this is the case
|
||||
// a mutable output directory must be specified using "-artifact_prefix=...",
|
||||
// so write the log file(s) there.
|
||||
int FdOut = STDOUT_FILENO;
|
||||
|
||||
if (Cmd.hasOutputFile()) {
|
||||
auto Filename = Cmd.getOutputFile();
|
||||
FdOut = open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
|
||||
std::string Path;
|
||||
if (Cmd.hasFlag("artifact_prefix"))
|
||||
Path = Cmd.getFlagValue("artifact_prefix") + "/" + Cmd.getOutputFile();
|
||||
else
|
||||
Path = Cmd.getOutputFile();
|
||||
FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
|
||||
if (FdOut == -1) {
|
||||
Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(),
|
||||
Printf("libFuzzer: failed to open %s: %s\n", Path.c_str(),
|
||||
strerror(errno));
|
||||
return ZX_ERR_IO;
|
||||
}
|
||||
}
|
||||
auto CloseFdOut = at_scope_exit([&]() { close(FdOut); } );
|
||||
auto CloseFdOut = at_scope_exit([FdOut]() {
|
||||
if (FdOut != STDOUT_FILENO)
|
||||
close(FdOut);
|
||||
});
|
||||
|
||||
// Determine stderr
|
||||
int FdErr = STDERR_FILENO;
|
||||
|
|
@ -440,7 +446,7 @@ int ExecuteCommand(const Command &Cmd) {
|
|||
|
||||
// Now join the process and return the exit status.
|
||||
if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED,
|
||||
ZX_TIME_INFINITE_OLD, nullptr)) != ZX_OK) {
|
||||
ZX_TIME_INFINITE, nullptr)) != ZX_OK) {
|
||||
Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
|
||||
_zx_status_get_string(rc));
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#include <windows.h>
|
||||
|
||||
// This must be included after windows.h.
|
||||
#include <Psapi.h>
|
||||
#include <psapi.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
|
|
@ -179,7 +179,9 @@ const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
|
|||
}
|
||||
|
||||
std::string DisassembleCmd(const std::string &FileName) {
|
||||
if (ExecuteCommand("dumpbin /summary > nul") == 0)
|
||||
Vector<std::string> command_vector;
|
||||
command_vector.push_back("dumpbin /summary > nul");
|
||||
if (ExecuteCommand(Command(command_vector)) == 0)
|
||||
return "dumpbin /disasm " + FileName;
|
||||
Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
|
||||
exit(1);
|
||||
|
|
|
|||
|
|
@ -13,19 +13,20 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "hwasan.h"
|
||||
#include "hwasan_mapping.h"
|
||||
#include "hwasan_checks.h"
|
||||
#include "hwasan_poisoning.h"
|
||||
#include "hwasan_report.h"
|
||||
#include "hwasan_thread.h"
|
||||
#include "hwasan_thread_list.h"
|
||||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||
#include "sanitizer_common/sanitizer_symbolizer.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
#include "ubsan/ubsan_flags.h"
|
||||
#include "ubsan/ubsan_init.h"
|
||||
|
||||
|
|
@ -36,17 +37,17 @@ using namespace __sanitizer;
|
|||
namespace __hwasan {
|
||||
|
||||
void EnterSymbolizer() {
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
Thread *t = GetCurrentThread();
|
||||
CHECK(t);
|
||||
t->EnterSymbolizer();
|
||||
}
|
||||
void ExitSymbolizer() {
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
Thread *t = GetCurrentThread();
|
||||
CHECK(t);
|
||||
t->LeaveSymbolizer();
|
||||
}
|
||||
bool IsInSymbolizer() {
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
Thread *t = GetCurrentThread();
|
||||
return t && t->InSymbolizer();
|
||||
}
|
||||
|
||||
|
|
@ -57,6 +58,7 @@ Flags *flags() {
|
|||
}
|
||||
|
||||
int hwasan_inited = 0;
|
||||
int hwasan_shadow_inited = 0;
|
||||
bool hwasan_init_is_running;
|
||||
|
||||
int hwasan_report_count = 0;
|
||||
|
|
@ -86,7 +88,18 @@ static void InitializeFlags() {
|
|||
cf.check_printf = false;
|
||||
cf.intercept_tls_get_addr = true;
|
||||
cf.exitcode = 99;
|
||||
// Sigtrap is used in error reporting.
|
||||
cf.handle_sigtrap = kHandleSignalExclusive;
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
// Let platform handle other signals. It is better at reporting them then we
|
||||
// are.
|
||||
cf.handle_segv = kHandleSignalNo;
|
||||
cf.handle_sigbus = kHandleSignalNo;
|
||||
cf.handle_abort = kHandleSignalNo;
|
||||
cf.handle_sigill = kHandleSignalNo;
|
||||
cf.handle_sigfpe = kHandleSignalNo;
|
||||
#endif
|
||||
OverrideCommonFlags(cf);
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +132,8 @@ static void InitializeFlags() {
|
|||
#if HWASAN_CONTAINS_UBSAN
|
||||
ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
|
||||
#endif
|
||||
VPrintf(1, "HWASAN_OPTIONS: %s\n", hwasan_options ? hwasan_options : "<empty>");
|
||||
VPrintf(1, "HWASAN_OPTIONS: %s\n",
|
||||
hwasan_options ? hwasan_options : "<empty>");
|
||||
|
||||
InitializeCommonFlags();
|
||||
|
||||
|
|
@ -130,8 +144,13 @@ static void InitializeFlags() {
|
|||
|
||||
void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
|
||||
void *context, bool request_fast_unwind) {
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) {
|
||||
Thread *t = GetCurrentThread();
|
||||
if (!t) {
|
||||
// the thread is still being created.
|
||||
stack->size = 0;
|
||||
return;
|
||||
}
|
||||
if (!StackTrace::WillUseFastUnwind(request_fast_unwind)) {
|
||||
// Block reports from our interceptors during _Unwind_Backtrace.
|
||||
SymbolizerScope sym_scope;
|
||||
return stack->Unwind(max_s, pc, bp, context, 0, 0, request_fast_unwind);
|
||||
|
|
@ -140,11 +159,6 @@ void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
|
|||
request_fast_unwind);
|
||||
}
|
||||
|
||||
void PrintWarning(uptr pc, uptr bp) {
|
||||
GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
|
||||
ReportInvalidAccess(&stack, 0);
|
||||
}
|
||||
|
||||
static void HWAsanCheckFailed(const char *file, int line, const char *cond,
|
||||
u64 v1, u64 v2) {
|
||||
Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
|
||||
|
|
@ -153,6 +167,84 @@ static void HWAsanCheckFailed(const char *file, int line, const char *cond,
|
|||
Die();
|
||||
}
|
||||
|
||||
static constexpr uptr kMemoryUsageBufferSize = 4096;
|
||||
|
||||
static void HwasanFormatMemoryUsage(InternalScopedString &s) {
|
||||
HwasanThreadList &thread_list = hwasanThreadList();
|
||||
auto thread_stats = thread_list.GetThreadStats();
|
||||
auto *sds = StackDepotGetStats();
|
||||
AllocatorStatCounters asc;
|
||||
GetAllocatorStats(asc);
|
||||
s.append(
|
||||
"HWASAN pid: %d rss: %zd threads: %zd stacks: %zd"
|
||||
" thr_aux: %zd stack_depot: %zd uniq_stacks: %zd"
|
||||
" heap: %zd",
|
||||
internal_getpid(), GetRSS(), thread_stats.n_live_threads,
|
||||
thread_stats.total_stack_size,
|
||||
thread_stats.n_live_threads * thread_list.MemoryUsedPerThread(),
|
||||
sds->allocated, sds->n_uniq_ids, asc[AllocatorStatMapped]);
|
||||
}
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
static char *memory_usage_buffer = nullptr;
|
||||
|
||||
#define PR_SET_VMA 0x53564d41
|
||||
#define PR_SET_VMA_ANON_NAME 0
|
||||
|
||||
static void InitMemoryUsage() {
|
||||
memory_usage_buffer =
|
||||
(char *)MmapOrDie(kMemoryUsageBufferSize, "memory usage string");
|
||||
CHECK(memory_usage_buffer);
|
||||
memory_usage_buffer[0] = '\0';
|
||||
CHECK(internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME,
|
||||
(uptr)memory_usage_buffer, kMemoryUsageBufferSize,
|
||||
(uptr)memory_usage_buffer) == 0);
|
||||
}
|
||||
|
||||
void UpdateMemoryUsage() {
|
||||
if (!flags()->export_memory_stats)
|
||||
return;
|
||||
if (!memory_usage_buffer)
|
||||
InitMemoryUsage();
|
||||
InternalScopedString s(kMemoryUsageBufferSize);
|
||||
HwasanFormatMemoryUsage(s);
|
||||
internal_strncpy(memory_usage_buffer, s.data(), kMemoryUsageBufferSize - 1);
|
||||
memory_usage_buffer[kMemoryUsageBufferSize - 1] = '\0';
|
||||
}
|
||||
#else
|
||||
void UpdateMemoryUsage() {}
|
||||
#endif
|
||||
|
||||
struct FrameDescription {
|
||||
uptr PC;
|
||||
const char *Descr;
|
||||
};
|
||||
|
||||
struct FrameDescriptionArray {
|
||||
FrameDescription *beg, *end;
|
||||
};
|
||||
|
||||
static InternalMmapVectorNoCtor<FrameDescriptionArray> AllFrames;
|
||||
|
||||
void InitFrameDescriptors(uptr b, uptr e) {
|
||||
FrameDescription *beg = reinterpret_cast<FrameDescription *>(b);
|
||||
FrameDescription *end = reinterpret_cast<FrameDescription *>(e);
|
||||
if (beg == end)
|
||||
return;
|
||||
AllFrames.push_back({beg, end});
|
||||
if (Verbosity())
|
||||
for (FrameDescription *frame_descr = beg; frame_descr < end; frame_descr++)
|
||||
Printf("Frame: %p %s\n", frame_descr->PC, frame_descr->Descr);
|
||||
}
|
||||
|
||||
const char *GetStackFrameDescr(uptr pc) {
|
||||
for (uptr i = 0, n = AllFrames.size(); i < n; i++)
|
||||
for (auto p = AllFrames[i].beg; p < AllFrames[i].end; p++)
|
||||
if (p->PC == pc)
|
||||
return p->Descr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace __hwasan
|
||||
|
||||
// Interface.
|
||||
|
|
@ -161,6 +253,20 @@ using namespace __hwasan;
|
|||
|
||||
uptr __hwasan_shadow_memory_dynamic_address; // Global interface symbol.
|
||||
|
||||
void __hwasan_shadow_init() {
|
||||
if (hwasan_shadow_inited) return;
|
||||
if (!InitShadow()) {
|
||||
Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n");
|
||||
DumpProcessMap();
|
||||
Die();
|
||||
}
|
||||
hwasan_shadow_inited = 1;
|
||||
}
|
||||
|
||||
void __hwasan_init_frames(uptr beg, uptr end) {
|
||||
InitFrameDescriptors(beg, end);
|
||||
}
|
||||
|
||||
void __hwasan_init() {
|
||||
CHECK(!hwasan_init_is_running);
|
||||
if (hwasan_inited) return;
|
||||
|
|
@ -177,18 +283,20 @@ void __hwasan_init() {
|
|||
|
||||
__sanitizer_set_report_path(common_flags()->log_path);
|
||||
|
||||
AndroidTestTlsSlot();
|
||||
|
||||
DisableCoreDumperIfNecessary();
|
||||
if (!InitShadow()) {
|
||||
Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n");
|
||||
if (HWASAN_FIXED_MAPPING) {
|
||||
Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
|
||||
Printf("FATAL: Disabling ASLR is known to cause this error.\n");
|
||||
Printf("FATAL: If running under GDB, try "
|
||||
"'set disable-randomization off'.\n");
|
||||
}
|
||||
DumpProcessMap();
|
||||
Die();
|
||||
}
|
||||
|
||||
__hwasan_shadow_init();
|
||||
|
||||
InitThreads();
|
||||
hwasanThreadList().CreateCurrentThread();
|
||||
|
||||
MadviseShadow();
|
||||
|
||||
SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
|
||||
// This may call libc -> needs initialized shadow.
|
||||
AndroidLogInit();
|
||||
|
||||
InitializeInterceptors();
|
||||
InstallDeadlySignalHandlers(HwasanOnDeadlySignal);
|
||||
|
|
@ -198,14 +306,11 @@ void __hwasan_init() {
|
|||
|
||||
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
|
||||
|
||||
HwasanTSDInit(HwasanTSDDtor);
|
||||
HwasanTSDInit();
|
||||
HwasanTSDThreadInit();
|
||||
|
||||
HwasanAllocatorInit();
|
||||
|
||||
HwasanThread *main_thread = HwasanThread::Create(nullptr, nullptr);
|
||||
SetCurrentThread(main_thread);
|
||||
main_thread->ThreadStart();
|
||||
|
||||
#if HWASAN_CONTAINS_UBSAN
|
||||
__ubsan::InitAsPlugin();
|
||||
#endif
|
||||
|
|
@ -216,9 +321,14 @@ void __hwasan_init() {
|
|||
hwasan_inited = 1;
|
||||
}
|
||||
|
||||
void __hwasan_print_shadow(const void *x, uptr size) {
|
||||
// FIXME:
|
||||
Printf("FIXME: __hwasan_print_shadow unimplemented\n");
|
||||
void __hwasan_print_shadow(const void *p, uptr sz) {
|
||||
uptr ptr_raw = UntagAddr(reinterpret_cast<uptr>(p));
|
||||
uptr shadow_first = MemToShadow(ptr_raw);
|
||||
uptr shadow_last = MemToShadow(ptr_raw + sz - 1);
|
||||
Printf("HWASan shadow map for %zx .. %zx (pointer tag %x)\n", ptr_raw,
|
||||
ptr_raw + sz, GetTagFromPointer((uptr)p));
|
||||
for (uptr s = shadow_first; s <= shadow_last; ++s)
|
||||
Printf(" %zx: %x\n", ShadowToMem(s), *(tag_t *)s);
|
||||
}
|
||||
|
||||
sptr __hwasan_test_shadow(const void *p, uptr sz) {
|
||||
|
|
@ -227,12 +337,12 @@ sptr __hwasan_test_shadow(const void *p, uptr sz) {
|
|||
tag_t ptr_tag = GetTagFromPointer((uptr)p);
|
||||
if (ptr_tag == 0)
|
||||
return -1;
|
||||
uptr ptr_raw = GetAddressFromPointer((uptr)p);
|
||||
uptr shadow_first = MEM_TO_SHADOW(ptr_raw);
|
||||
uptr shadow_last = MEM_TO_SHADOW(ptr_raw + sz - 1);
|
||||
uptr ptr_raw = UntagAddr(reinterpret_cast<uptr>(p));
|
||||
uptr shadow_first = MemToShadow(ptr_raw);
|
||||
uptr shadow_last = MemToShadow(ptr_raw + sz - 1);
|
||||
for (uptr s = shadow_first; s <= shadow_last; ++s)
|
||||
if (*(tag_t*)s != ptr_tag)
|
||||
return SHADOW_TO_MEM(s) - ptr_raw;
|
||||
return ShadowToMem(s) - ptr_raw;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -255,63 +365,6 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
|
|||
*p = x;
|
||||
}
|
||||
|
||||
template<unsigned X>
|
||||
__attribute__((always_inline))
|
||||
static void SigTrap(uptr p) {
|
||||
#if defined(__aarch64__)
|
||||
(void)p;
|
||||
// 0x900 is added to do not interfere with the kernel use of lower values of
|
||||
// brk immediate.
|
||||
// FIXME: Add a constraint to put the pointer into x0, the same as x86 branch.
|
||||
asm("brk %0\n\t" ::"n"(0x900 + X));
|
||||
#elif defined(__x86_64__)
|
||||
// INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
|
||||
// total. The pointer is passed via rdi.
|
||||
// 0x40 is added as a safeguard, to help distinguish our trap from others and
|
||||
// to avoid 0 offsets in the command (otherwise it'll be reduced to a
|
||||
// different nop command, the three bytes one).
|
||||
asm volatile(
|
||||
"int3\n"
|
||||
"nopl %c0(%%rax)\n"
|
||||
:: "n"(0x40 + X), "D"(p));
|
||||
#else
|
||||
// FIXME: not always sigill.
|
||||
__builtin_trap();
|
||||
#endif
|
||||
// __builtin_unreachable();
|
||||
}
|
||||
|
||||
enum class ErrorAction { Abort, Recover };
|
||||
enum class AccessType { Load, Store };
|
||||
|
||||
template <ErrorAction EA, AccessType AT, unsigned LogSize>
|
||||
__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
|
||||
tag_t ptr_tag = GetTagFromPointer(p);
|
||||
uptr ptr_raw = p & ~kAddressTagMask;
|
||||
tag_t mem_tag = *(tag_t *)MEM_TO_SHADOW(ptr_raw);
|
||||
if (UNLIKELY(ptr_tag != mem_tag)) {
|
||||
SigTrap<0x20 * (EA == ErrorAction::Recover) +
|
||||
0x10 * (AT == AccessType::Store) + LogSize>(p);
|
||||
if (EA == ErrorAction::Abort) __builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
template <ErrorAction EA, AccessType AT>
|
||||
__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
|
||||
uptr sz) {
|
||||
CHECK_NE(0, sz);
|
||||
tag_t ptr_tag = GetTagFromPointer(p);
|
||||
uptr ptr_raw = p & ~kAddressTagMask;
|
||||
tag_t *shadow_first = (tag_t *)MEM_TO_SHADOW(ptr_raw);
|
||||
tag_t *shadow_last = (tag_t *)MEM_TO_SHADOW(ptr_raw + sz - 1);
|
||||
for (tag_t *t = shadow_first; t <= shadow_last; ++t)
|
||||
if (UNLIKELY(ptr_tag != *t)) {
|
||||
SigTrap<0x20 * (EA == ErrorAction::Recover) +
|
||||
0x10 * (AT == AccessType::Store) + 0xf>(p);
|
||||
if (EA == ErrorAction::Abort) __builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
void __hwasan_loadN(uptr p, uptr sz) {
|
||||
CheckAddressSized<ErrorAction::Abort, AccessType::Load>(p, sz);
|
||||
}
|
||||
|
|
@ -392,10 +445,38 @@ void __hwasan_tag_memory(uptr p, u8 tag, uptr sz) {
|
|||
TagMemoryAligned(p, sz, tag);
|
||||
}
|
||||
|
||||
uptr __hwasan_tag_pointer(uptr p, u8 tag) {
|
||||
return AddTagToPointer(p, tag);
|
||||
}
|
||||
|
||||
void __hwasan_handle_longjmp(const void *sp_dst) {
|
||||
uptr dst = (uptr)sp_dst;
|
||||
// HWASan does not support tagged SP.
|
||||
CHECK(GetTagFromPointer(dst) == 0);
|
||||
|
||||
uptr sp = (uptr)__builtin_frame_address(0);
|
||||
static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M
|
||||
if (dst < sp || dst - sp > kMaxExpectedCleanupSize) {
|
||||
Report(
|
||||
"WARNING: HWASan is ignoring requested __hwasan_handle_longjmp: "
|
||||
"stack top: %p; target %p; distance: %p (%zd)\n"
|
||||
"False positive error reports may follow\n",
|
||||
(void *)sp, (void *)dst, dst - sp);
|
||||
return;
|
||||
}
|
||||
TagMemory(sp, dst - sp, 0);
|
||||
}
|
||||
|
||||
void __hwasan_print_memory_usage() {
|
||||
InternalScopedString s(kMemoryUsageBufferSize);
|
||||
HwasanFormatMemoryUsage(s);
|
||||
Printf("%s\n", s.data());
|
||||
}
|
||||
|
||||
static const u8 kFallbackTag = 0xBB;
|
||||
|
||||
u8 __hwasan_generate_tag() {
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
Thread *t = GetCurrentThread();
|
||||
if (!t) return kFallbackTag;
|
||||
return t->GenerateRandomTag();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@
|
|||
# define HWASAN_CONTAINS_UBSAN CAN_SANITIZE_UB
|
||||
#endif
|
||||
|
||||
#ifndef HWASAN_WITH_INTERCEPTORS
|
||||
#define HWASAN_WITH_INTERCEPTORS 0
|
||||
#endif
|
||||
|
||||
typedef u8 tag_t;
|
||||
|
||||
// TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address
|
||||
|
|
@ -37,16 +41,21 @@ typedef u8 tag_t;
|
|||
const unsigned kAddressTagShift = 56;
|
||||
const uptr kAddressTagMask = 0xFFUL << kAddressTagShift;
|
||||
|
||||
// Minimal alignment of the shadow base address. Determines the space available
|
||||
// for threads and stack histories. This is an ABI constant.
|
||||
const unsigned kShadowBaseAlignment = 32;
|
||||
|
||||
static inline tag_t GetTagFromPointer(uptr p) {
|
||||
return p >> kAddressTagShift;
|
||||
}
|
||||
|
||||
static inline uptr GetAddressFromPointer(uptr p) {
|
||||
return p & ~kAddressTagMask;
|
||||
static inline uptr UntagAddr(uptr tagged_addr) {
|
||||
return tagged_addr & ~kAddressTagMask;
|
||||
}
|
||||
|
||||
static inline void * GetAddressFromPointer(const void *p) {
|
||||
return (void *)((uptr)p & ~kAddressTagMask);
|
||||
static inline void *UntagPtr(const void *tagged_ptr) {
|
||||
return reinterpret_cast<void *>(
|
||||
UntagAddr(reinterpret_cast<uptr>(tagged_ptr)));
|
||||
}
|
||||
|
||||
static inline uptr AddTagToPointer(uptr p, tag_t tag) {
|
||||
|
|
@ -61,12 +70,13 @@ extern int hwasan_report_count;
|
|||
|
||||
bool ProtectRange(uptr beg, uptr end);
|
||||
bool InitShadow();
|
||||
void InitThreads();
|
||||
void MadviseShadow();
|
||||
char *GetProcSelfMaps();
|
||||
void InitializeInterceptors();
|
||||
|
||||
void HwasanAllocatorInit();
|
||||
void HwasanAllocatorThreadFinish();
|
||||
void HwasanDeallocate(StackTrace *stack, void *ptr);
|
||||
|
||||
void *hwasan_malloc(uptr size, StackTrace *stack);
|
||||
void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack);
|
||||
|
|
@ -77,11 +87,13 @@ void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack);
|
|||
void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack);
|
||||
int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
|
||||
StackTrace *stack);
|
||||
void hwasan_free(void *ptr, StackTrace *stack);
|
||||
|
||||
void InstallTrapHandler();
|
||||
void InstallAtExitHandler();
|
||||
|
||||
const char *GetStackOriginDescr(u32 id, uptr *pc);
|
||||
const char *GetStackFrameDescr(uptr pc);
|
||||
|
||||
void EnterSymbolizer();
|
||||
void ExitSymbolizer();
|
||||
|
|
@ -92,8 +104,6 @@ struct SymbolizerScope {
|
|||
~SymbolizerScope() { ExitSymbolizer(); }
|
||||
};
|
||||
|
||||
void PrintWarning(uptr pc, uptr bp);
|
||||
|
||||
void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
|
||||
void *context, bool request_fast_unwind);
|
||||
|
||||
|
|
@ -135,13 +145,17 @@ class ScopedThreadLocalStateBackup {
|
|||
u64 va_arg_overflow_size_tls;
|
||||
};
|
||||
|
||||
void HwasanTSDInit(void (*destructor)(void *tsd));
|
||||
void *HwasanTSDGet();
|
||||
void HwasanTSDSet(void *tsd);
|
||||
void HwasanTSDDtor(void *tsd);
|
||||
void HwasanTSDInit();
|
||||
void HwasanTSDThreadInit();
|
||||
|
||||
void HwasanOnDeadlySignal(int signo, void *info, void *context);
|
||||
|
||||
void UpdateMemoryUsage();
|
||||
|
||||
void AppendToErrorMessageBuffer(const char *buffer);
|
||||
|
||||
void AndroidTestTlsSlot();
|
||||
|
||||
} // namespace __hwasan
|
||||
|
||||
#define HWASAN_MALLOC_HOOK(ptr, size) \
|
||||
|
|
|
|||
|
|
@ -12,10 +12,6 @@
|
|||
// HWAddressSanitizer allocator.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
#include "sanitizer_common/sanitizer_allocator_checks.h"
|
||||
#include "sanitizer_common/sanitizer_allocator_interface.h"
|
||||
#include "sanitizer_common/sanitizer_allocator_report.h"
|
||||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_errno.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
|
|
@ -23,30 +19,53 @@
|
|||
#include "hwasan_allocator.h"
|
||||
#include "hwasan_mapping.h"
|
||||
#include "hwasan_thread.h"
|
||||
#include "hwasan_poisoning.h"
|
||||
#include "hwasan_report.h"
|
||||
|
||||
#if HWASAN_WITH_INTERCEPTORS
|
||||
DEFINE_REAL(void *, realloc, void *ptr, uptr size)
|
||||
DEFINE_REAL(void, free, void *ptr)
|
||||
#endif
|
||||
|
||||
namespace __hwasan {
|
||||
|
||||
enum {
|
||||
CHUNK_INVALID = 0,
|
||||
CHUNK_FREE = 1,
|
||||
CHUNK_ALLOCATED = 2
|
||||
static Allocator allocator;
|
||||
static AllocatorCache fallback_allocator_cache;
|
||||
static SpinMutex fallback_mutex;
|
||||
static atomic_uint8_t hwasan_allocator_tagging_enabled;
|
||||
|
||||
static const tag_t kFallbackAllocTag = 0xBB;
|
||||
static const tag_t kFallbackFreeTag = 0xBC;
|
||||
|
||||
enum RightAlignMode {
|
||||
kRightAlignNever,
|
||||
kRightAlignSometimes,
|
||||
kRightAlignAlways
|
||||
};
|
||||
|
||||
struct Metadata {
|
||||
u64 state : 2;
|
||||
u64 requested_size : 62;
|
||||
u32 alloc_context_id;
|
||||
u32 free_context_id;
|
||||
};
|
||||
// These two variables are initialized from flags()->malloc_align_right
|
||||
// in HwasanAllocatorInit and are never changed afterwards.
|
||||
static RightAlignMode right_align_mode = kRightAlignNever;
|
||||
static bool right_align_8 = false;
|
||||
|
||||
// Initialized in HwasanAllocatorInit, an never changed.
|
||||
static ALIGNED(16) u8 tail_magic[kShadowAlignment];
|
||||
|
||||
bool HwasanChunkView::IsValid() const {
|
||||
return metadata_ && metadata_->state != CHUNK_INVALID;
|
||||
}
|
||||
bool HwasanChunkView::IsAllocated() const {
|
||||
return metadata_ && metadata_->state == CHUNK_ALLOCATED;
|
||||
return metadata_ && metadata_->alloc_context_id && metadata_->requested_size;
|
||||
}
|
||||
|
||||
// Aligns the 'addr' right to the granule boundary.
|
||||
static uptr AlignRight(uptr addr, uptr requested_size) {
|
||||
uptr tail_size = requested_size % kShadowAlignment;
|
||||
if (!tail_size) return addr;
|
||||
if (right_align_8)
|
||||
return tail_size > 8 ? addr : addr + 8;
|
||||
return addr + kShadowAlignment - tail_size;
|
||||
}
|
||||
|
||||
uptr HwasanChunkView::Beg() const {
|
||||
if (metadata_ && metadata_->right_aligned)
|
||||
return AlignRight(block_, metadata_->requested_size);
|
||||
return block_;
|
||||
}
|
||||
uptr HwasanChunkView::End() const {
|
||||
|
|
@ -58,88 +77,79 @@ uptr HwasanChunkView::UsedSize() const {
|
|||
u32 HwasanChunkView::GetAllocStackId() const {
|
||||
return metadata_->alloc_context_id;
|
||||
}
|
||||
u32 HwasanChunkView::GetFreeStackId() const {
|
||||
return metadata_->free_context_id;
|
||||
|
||||
uptr HwasanChunkView::ActualSize() const {
|
||||
return allocator.GetActuallyAllocatedSize(reinterpret_cast<void *>(block_));
|
||||
}
|
||||
|
||||
struct HwasanMapUnmapCallback {
|
||||
void OnMap(uptr p, uptr size) const {}
|
||||
void OnUnmap(uptr p, uptr size) const {
|
||||
// We are about to unmap a chunk of user memory.
|
||||
// It can return as user-requested mmap() or another thread stack.
|
||||
// Make it accessible with zero-tagged pointer.
|
||||
TagMemory(p, size, 0);
|
||||
}
|
||||
};
|
||||
bool HwasanChunkView::FromSmallHeap() const {
|
||||
return allocator.FromPrimary(reinterpret_cast<void *>(block_));
|
||||
}
|
||||
|
||||
#if !defined(__aarch64__) && !defined(__x86_64__)
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
|
||||
static const uptr kRegionSizeLog = 20;
|
||||
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
||||
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
|
||||
|
||||
struct AP32 {
|
||||
static const uptr kSpaceBeg = 0;
|
||||
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
|
||||
static const uptr kMetadataSize = sizeof(Metadata);
|
||||
typedef __sanitizer::CompactSizeClassMap SizeClassMap;
|
||||
static const uptr kRegionSizeLog = __hwasan::kRegionSizeLog;
|
||||
typedef __hwasan::ByteMap ByteMap;
|
||||
typedef HwasanMapUnmapCallback MapUnmapCallback;
|
||||
static const uptr kFlags = 0;
|
||||
};
|
||||
typedef SizeClassAllocator32<AP32> PrimaryAllocator;
|
||||
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
||||
typedef LargeMmapAllocator<HwasanMapUnmapCallback> SecondaryAllocator;
|
||||
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
|
||||
SecondaryAllocator> Allocator;
|
||||
|
||||
static Allocator allocator;
|
||||
static AllocatorCache fallback_allocator_cache;
|
||||
static SpinMutex fallback_mutex;
|
||||
static atomic_uint8_t hwasan_allocator_tagging_enabled;
|
||||
|
||||
static const tag_t kFallbackAllocTag = 0xBB;
|
||||
static const tag_t kFallbackFreeTag = 0xBC;
|
||||
void GetAllocatorStats(AllocatorStatCounters s) {
|
||||
allocator.GetStats(s);
|
||||
}
|
||||
|
||||
void HwasanAllocatorInit() {
|
||||
atomic_store_relaxed(&hwasan_allocator_tagging_enabled,
|
||||
!flags()->disable_allocator_tagging);
|
||||
SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
|
||||
allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
|
||||
switch (flags()->malloc_align_right) {
|
||||
case 0: break;
|
||||
case 1:
|
||||
right_align_mode = kRightAlignSometimes;
|
||||
right_align_8 = false;
|
||||
break;
|
||||
case 2:
|
||||
right_align_mode = kRightAlignAlways;
|
||||
right_align_8 = false;
|
||||
break;
|
||||
case 8:
|
||||
right_align_mode = kRightAlignSometimes;
|
||||
right_align_8 = true;
|
||||
break;
|
||||
case 9:
|
||||
right_align_mode = kRightAlignAlways;
|
||||
right_align_8 = true;
|
||||
break;
|
||||
default:
|
||||
Report("ERROR: unsupported value of malloc_align_right flag: %d\n",
|
||||
flags()->malloc_align_right);
|
||||
Die();
|
||||
}
|
||||
for (uptr i = 0; i < kShadowAlignment; i++)
|
||||
tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
|
||||
}
|
||||
|
||||
AllocatorCache *GetAllocatorCache(HwasanThreadLocalMallocStorage *ms) {
|
||||
CHECK(ms);
|
||||
CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache));
|
||||
return reinterpret_cast<AllocatorCache *>(ms->allocator_cache);
|
||||
void AllocatorSwallowThreadLocalCache(AllocatorCache *cache) {
|
||||
allocator.SwallowCache(cache);
|
||||
}
|
||||
|
||||
void HwasanThreadLocalMallocStorage::CommitBack() {
|
||||
allocator.SwallowCache(GetAllocatorCache(this));
|
||||
static uptr TaggedSize(uptr size) {
|
||||
if (!size) size = 1;
|
||||
uptr new_size = RoundUpTo(size, kShadowAlignment);
|
||||
CHECK_GE(new_size, size);
|
||||
return new_size;
|
||||
}
|
||||
|
||||
static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,
|
||||
bool zeroise) {
|
||||
alignment = Max(alignment, kShadowAlignment);
|
||||
size = RoundUpTo(size, kShadowAlignment);
|
||||
|
||||
if (size > kMaxAllowedMallocSize) {
|
||||
static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
|
||||
bool zeroise) {
|
||||
if (orig_size > kMaxAllowedMallocSize) {
|
||||
if (AllocatorMayReturnNull()) {
|
||||
Report("WARNING: HWAddressSanitizer failed to allocate 0x%zx bytes\n",
|
||||
size);
|
||||
orig_size);
|
||||
return nullptr;
|
||||
}
|
||||
ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, stack);
|
||||
ReportAllocationSizeTooBig(orig_size, kMaxAllowedMallocSize, stack);
|
||||
}
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
|
||||
alignment = Max(alignment, kShadowAlignment);
|
||||
uptr size = TaggedSize(orig_size);
|
||||
Thread *t = GetCurrentThread();
|
||||
void *allocated;
|
||||
if (t) {
|
||||
AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
|
||||
allocated = allocator.Allocate(cache, size, alignment);
|
||||
allocated = allocator.Allocate(t->allocator_cache(), size, alignment);
|
||||
} else {
|
||||
SpinMutexLock l(&fallback_mutex);
|
||||
AllocatorCache *cache = &fallback_allocator_cache;
|
||||
|
|
@ -153,11 +163,18 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,
|
|||
}
|
||||
Metadata *meta =
|
||||
reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
|
||||
meta->state = CHUNK_ALLOCATED;
|
||||
meta->requested_size = size;
|
||||
meta->requested_size = static_cast<u32>(orig_size);
|
||||
meta->alloc_context_id = StackDepotPut(*stack);
|
||||
if (zeroise)
|
||||
meta->right_aligned = false;
|
||||
if (zeroise) {
|
||||
internal_memset(allocated, 0, size);
|
||||
} else if (flags()->max_malloc_fill_size > 0) {
|
||||
uptr fill_size = Min(size, (uptr)flags()->max_malloc_fill_size);
|
||||
internal_memset(allocated, flags()->malloc_fill_byte, fill_size);
|
||||
}
|
||||
if (!right_align_mode)
|
||||
internal_memcpy(reinterpret_cast<u8 *>(allocated) + orig_size, tail_magic,
|
||||
size - orig_size);
|
||||
|
||||
void *user_ptr = allocated;
|
||||
if (flags()->tag_in_malloc &&
|
||||
|
|
@ -165,74 +182,101 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,
|
|||
user_ptr = (void *)TagMemoryAligned(
|
||||
(uptr)user_ptr, size, t ? t->GenerateRandomTag() : kFallbackAllocTag);
|
||||
|
||||
if ((orig_size % kShadowAlignment) && (alignment <= kShadowAlignment) &&
|
||||
right_align_mode) {
|
||||
uptr as_uptr = reinterpret_cast<uptr>(user_ptr);
|
||||
if (right_align_mode == kRightAlignAlways ||
|
||||
GetTagFromPointer(as_uptr) & 1) { // use a tag bit as a random bit.
|
||||
user_ptr = reinterpret_cast<void *>(AlignRight(as_uptr, orig_size));
|
||||
meta->right_aligned = 1;
|
||||
}
|
||||
}
|
||||
|
||||
HWASAN_MALLOC_HOOK(user_ptr, size);
|
||||
return user_ptr;
|
||||
}
|
||||
|
||||
void HwasanDeallocate(StackTrace *stack, void *user_ptr) {
|
||||
CHECK(user_ptr);
|
||||
HWASAN_FREE_HOOK(user_ptr);
|
||||
static bool PointerAndMemoryTagsMatch(void *tagged_ptr) {
|
||||
CHECK(tagged_ptr);
|
||||
tag_t ptr_tag = GetTagFromPointer(reinterpret_cast<uptr>(tagged_ptr));
|
||||
tag_t mem_tag = *reinterpret_cast<tag_t *>(
|
||||
MemToShadow(reinterpret_cast<uptr>(UntagPtr(tagged_ptr))));
|
||||
return ptr_tag == mem_tag;
|
||||
}
|
||||
|
||||
static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
|
||||
CHECK(tagged_ptr);
|
||||
HWASAN_FREE_HOOK(tagged_ptr);
|
||||
|
||||
if (!PointerAndMemoryTagsMatch(tagged_ptr))
|
||||
ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
|
||||
|
||||
void *untagged_ptr = UntagPtr(tagged_ptr);
|
||||
void *aligned_ptr = reinterpret_cast<void *>(
|
||||
RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
|
||||
Metadata *meta =
|
||||
reinterpret_cast<Metadata *>(allocator.GetMetaData(aligned_ptr));
|
||||
uptr orig_size = meta->requested_size;
|
||||
u32 free_context_id = StackDepotPut(*stack);
|
||||
u32 alloc_context_id = meta->alloc_context_id;
|
||||
|
||||
// Check tail magic.
|
||||
uptr tagged_size = TaggedSize(orig_size);
|
||||
if (flags()->free_checks_tail_magic && !right_align_mode && orig_size) {
|
||||
uptr tail_size = tagged_size - orig_size;
|
||||
CHECK_LT(tail_size, kShadowAlignment);
|
||||
void *tail_beg = reinterpret_cast<void *>(
|
||||
reinterpret_cast<uptr>(aligned_ptr) + orig_size);
|
||||
if (tail_size && internal_memcmp(tail_beg, tail_magic, tail_size))
|
||||
ReportTailOverwritten(stack, reinterpret_cast<uptr>(tagged_ptr),
|
||||
orig_size, tail_size, tail_magic);
|
||||
}
|
||||
|
||||
void *p = GetAddressFromPointer(user_ptr);
|
||||
Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p));
|
||||
uptr size = meta->requested_size;
|
||||
meta->state = CHUNK_FREE;
|
||||
meta->requested_size = 0;
|
||||
meta->free_context_id = StackDepotPut(*stack);
|
||||
meta->alloc_context_id = 0;
|
||||
// This memory will not be reused by anyone else, so we are free to keep it
|
||||
// poisoned.
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
Thread *t = GetCurrentThread();
|
||||
if (flags()->max_free_fill_size > 0) {
|
||||
uptr fill_size =
|
||||
Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size);
|
||||
internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size);
|
||||
}
|
||||
if (flags()->tag_in_free &&
|
||||
atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
|
||||
TagMemoryAligned((uptr)p, size,
|
||||
TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size),
|
||||
t ? t->GenerateRandomTag() : kFallbackFreeTag);
|
||||
if (t) {
|
||||
AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
|
||||
allocator.Deallocate(cache, p);
|
||||
allocator.Deallocate(t->allocator_cache(), aligned_ptr);
|
||||
if (auto *ha = t->heap_allocations())
|
||||
ha->push({reinterpret_cast<uptr>(tagged_ptr), alloc_context_id,
|
||||
free_context_id, static_cast<u32>(orig_size)});
|
||||
} else {
|
||||
SpinMutexLock l(&fallback_mutex);
|
||||
AllocatorCache *cache = &fallback_allocator_cache;
|
||||
allocator.Deallocate(cache, p);
|
||||
allocator.Deallocate(cache, aligned_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void *HwasanReallocate(StackTrace *stack, void *user_old_p, uptr new_size,
|
||||
uptr alignment) {
|
||||
alignment = Max(alignment, kShadowAlignment);
|
||||
new_size = RoundUpTo(new_size, kShadowAlignment);
|
||||
static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old,
|
||||
uptr new_size, uptr alignment) {
|
||||
if (!PointerAndMemoryTagsMatch(tagged_ptr_old))
|
||||
ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr_old));
|
||||
|
||||
void *old_p = GetAddressFromPointer(user_old_p);
|
||||
Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p));
|
||||
uptr old_size = meta->requested_size;
|
||||
uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p);
|
||||
if (new_size <= actually_allocated_size) {
|
||||
// We are not reallocating here.
|
||||
// FIXME: update stack trace for the allocation?
|
||||
meta->requested_size = new_size;
|
||||
if (!atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
|
||||
return user_old_p;
|
||||
if (flags()->retag_in_realloc) {
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
return (void *)TagMemoryAligned(
|
||||
(uptr)old_p, new_size,
|
||||
t ? t->GenerateRandomTag() : kFallbackAllocTag);
|
||||
}
|
||||
if (new_size > old_size) {
|
||||
tag_t tag = GetTagFromPointer((uptr)user_old_p);
|
||||
TagMemoryAligned((uptr)old_p + old_size, new_size - old_size, tag);
|
||||
}
|
||||
return user_old_p;
|
||||
void *tagged_ptr_new =
|
||||
HwasanAllocate(stack, new_size, alignment, false /*zeroise*/);
|
||||
if (tagged_ptr_old && tagged_ptr_new) {
|
||||
void *untagged_ptr_old = UntagPtr(tagged_ptr_old);
|
||||
Metadata *meta =
|
||||
reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr_old));
|
||||
internal_memcpy(UntagPtr(tagged_ptr_new), untagged_ptr_old,
|
||||
Min(new_size, static_cast<uptr>(meta->requested_size)));
|
||||
HwasanDeallocate(stack, tagged_ptr_old);
|
||||
}
|
||||
uptr memcpy_size = Min(new_size, old_size);
|
||||
void *new_p = HwasanAllocate(stack, new_size, alignment, false /*zeroise*/);
|
||||
if (new_p) {
|
||||
internal_memcpy(new_p, old_p, memcpy_size);
|
||||
HwasanDeallocate(stack, old_p);
|
||||
}
|
||||
return new_p;
|
||||
return tagged_ptr_new;
|
||||
}
|
||||
|
||||
void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
|
||||
static void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
|
||||
if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
|
||||
if (AllocatorMayReturnNull())
|
||||
return nullptr;
|
||||
|
|
@ -250,12 +294,18 @@ HwasanChunkView FindHeapChunkByAddress(uptr address) {
|
|||
return HwasanChunkView(reinterpret_cast<uptr>(block), metadata);
|
||||
}
|
||||
|
||||
static uptr AllocationSize(const void *user_ptr) {
|
||||
const void *p = GetAddressFromPointer(user_ptr);
|
||||
if (!p) return 0;
|
||||
const void *beg = allocator.GetBlockBegin(p);
|
||||
if (beg != p) return 0;
|
||||
Metadata *b = (Metadata *)allocator.GetMetaData(p);
|
||||
static uptr AllocationSize(const void *tagged_ptr) {
|
||||
const void *untagged_ptr = UntagPtr(tagged_ptr);
|
||||
if (!untagged_ptr) return 0;
|
||||
const void *beg = allocator.GetBlockBegin(untagged_ptr);
|
||||
Metadata *b = (Metadata *)allocator.GetMetaData(untagged_ptr);
|
||||
if (b->right_aligned) {
|
||||
if (beg != reinterpret_cast<void *>(RoundDownTo(
|
||||
reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment)))
|
||||
return 0;
|
||||
} else {
|
||||
if (beg != untagged_ptr) return 0;
|
||||
}
|
||||
return b->requested_size;
|
||||
}
|
||||
|
||||
|
|
@ -270,6 +320,14 @@ void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
|
|||
void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) {
|
||||
if (!ptr)
|
||||
return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false));
|
||||
|
||||
#if HWASAN_WITH_INTERCEPTORS
|
||||
// A tag of 0 means that this is a system allocator allocation, so we must use
|
||||
// the system allocator to realloc it.
|
||||
if (!flags()->disable_allocator_tagging && GetTagFromPointer((uptr)ptr) == 0)
|
||||
return REAL(realloc)(ptr, size);
|
||||
#endif
|
||||
|
||||
if (size == 0) {
|
||||
HwasanDeallocate(stack, ptr);
|
||||
return nullptr;
|
||||
|
|
@ -331,6 +389,17 @@ int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void hwasan_free(void *ptr, StackTrace *stack) {
|
||||
#if HWASAN_WITH_INTERCEPTORS
|
||||
// A tag of 0 means that this is a system allocator allocation, so we must use
|
||||
// the system allocator to free it.
|
||||
if (!flags()->disable_allocator_tagging && GetTagFromPointer((uptr)ptr) == 0)
|
||||
return REAL(free)(ptr);
|
||||
#endif
|
||||
|
||||
return HwasanDeallocate(stack, ptr);
|
||||
}
|
||||
|
||||
} // namespace __hwasan
|
||||
|
||||
using namespace __hwasan;
|
||||
|
|
@ -340,6 +409,15 @@ void __hwasan_enable_allocator_tagging() {
|
|||
}
|
||||
|
||||
void __hwasan_disable_allocator_tagging() {
|
||||
#if HWASAN_WITH_INTERCEPTORS
|
||||
// Allocator tagging must be enabled for the system allocator fallback to work
|
||||
// correctly. This means that we can't disable it at runtime if it was enabled
|
||||
// at startup since that might result in our deallocations going to the system
|
||||
// allocator. If tagging was disabled at startup we avoid this problem by
|
||||
// disabling the fallback altogether.
|
||||
CHECK(flags()->disable_allocator_tagging);
|
||||
#endif
|
||||
|
||||
atomic_store_relaxed(&hwasan_allocator_tagging_enabled, 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===-- hwasan_allocator.h ----------------------------------------*- C++ -*-===//
|
||||
//===-- hwasan_allocator.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -14,35 +14,73 @@
|
|||
#ifndef HWASAN_ALLOCATOR_H
|
||||
#define HWASAN_ALLOCATOR_H
|
||||
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
#include "sanitizer_common/sanitizer_allocator_checks.h"
|
||||
#include "sanitizer_common/sanitizer_allocator_interface.h"
|
||||
#include "sanitizer_common/sanitizer_allocator_report.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_ring_buffer.h"
|
||||
#include "hwasan_poisoning.h"
|
||||
|
||||
#if !defined(__aarch64__) && !defined(__x86_64__)
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
#if HWASAN_WITH_INTERCEPTORS
|
||||
DECLARE_REAL(void *, realloc, void *ptr, uptr size)
|
||||
DECLARE_REAL(void, free, void *ptr)
|
||||
#endif
|
||||
|
||||
namespace __hwasan {
|
||||
|
||||
struct HwasanThreadLocalMallocStorage {
|
||||
uptr quarantine_cache[16];
|
||||
// Allocator cache contains atomic_uint64_t which must be 8-byte aligned.
|
||||
ALIGNED(8) uptr allocator_cache[96 * (512 * 8 + 16)]; // Opaque.
|
||||
void CommitBack();
|
||||
|
||||
private:
|
||||
// These objects are allocated via mmap() and are zero-initialized.
|
||||
HwasanThreadLocalMallocStorage() {}
|
||||
struct Metadata {
|
||||
u32 requested_size : 31; // sizes are < 2G.
|
||||
u32 right_aligned : 1;
|
||||
u32 alloc_context_id;
|
||||
};
|
||||
|
||||
struct Metadata;
|
||||
struct HwasanMapUnmapCallback {
|
||||
void OnMap(uptr p, uptr size) const { UpdateMemoryUsage(); }
|
||||
void OnUnmap(uptr p, uptr size) const {
|
||||
// We are about to unmap a chunk of user memory.
|
||||
// It can return as user-requested mmap() or another thread stack.
|
||||
// Make it accessible with zero-tagged pointer.
|
||||
TagMemory(p, size, 0);
|
||||
}
|
||||
};
|
||||
|
||||
static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
|
||||
|
||||
struct AP64 {
|
||||
static const uptr kSpaceBeg = ~0ULL;
|
||||
static const uptr kSpaceSize = 0x2000000000ULL;
|
||||
static const uptr kMetadataSize = sizeof(Metadata);
|
||||
typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
|
||||
using AddressSpaceView = LocalAddressSpaceView;
|
||||
typedef HwasanMapUnmapCallback MapUnmapCallback;
|
||||
static const uptr kFlags = 0;
|
||||
};
|
||||
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
|
||||
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
||||
typedef LargeMmapAllocator<HwasanMapUnmapCallback> SecondaryAllocator;
|
||||
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
|
||||
SecondaryAllocator> Allocator;
|
||||
|
||||
void AllocatorSwallowThreadLocalCache(AllocatorCache *cache);
|
||||
|
||||
class HwasanChunkView {
|
||||
public:
|
||||
HwasanChunkView() : block_(0), metadata_(nullptr) {}
|
||||
HwasanChunkView(uptr block, Metadata *metadata)
|
||||
: block_(block), metadata_(metadata) {}
|
||||
bool IsValid() const; // Checks if it points to a valid allocated chunk
|
||||
bool IsAllocated() const; // Checks if the memory is currently allocated
|
||||
uptr Beg() const; // First byte of user memory
|
||||
uptr End() const; // Last byte of user memory
|
||||
uptr UsedSize() const; // Size requested by the user
|
||||
uptr ActualSize() const; // Size allocated by the allocator.
|
||||
u32 GetAllocStackId() const;
|
||||
u32 GetFreeStackId() const;
|
||||
bool FromSmallHeap() const;
|
||||
private:
|
||||
uptr block_;
|
||||
Metadata *const metadata_;
|
||||
|
|
@ -50,6 +88,21 @@ class HwasanChunkView {
|
|||
|
||||
HwasanChunkView FindHeapChunkByAddress(uptr address);
|
||||
|
||||
// Information about one (de)allocation that happened in the past.
|
||||
// These are recorded in a thread-local ring buffer.
|
||||
// TODO: this is currently 24 bytes (20 bytes + alignment).
|
||||
// Compress it to 16 bytes or extend it to be more useful.
|
||||
struct HeapAllocationRecord {
|
||||
uptr tagged_addr;
|
||||
u32 alloc_context_id;
|
||||
u32 free_context_id;
|
||||
u32 requested_size;
|
||||
};
|
||||
|
||||
typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
|
||||
|
||||
void GetAllocatorStats(AllocatorStatCounters s);
|
||||
|
||||
} // namespace __hwasan
|
||||
|
||||
#endif // HWASAN_ALLOCATOR_H
|
||||
|
|
|
|||
80
contrib/compiler-rt/lib/hwasan/hwasan_checks.h
Normal file
80
contrib/compiler-rt/lib/hwasan/hwasan_checks.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
//===-- hwasan_checks.h -----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of HWAddressSanitizer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef HWASAN_CHECKS_H
|
||||
#define HWASAN_CHECKS_H
|
||||
|
||||
#include "hwasan_mapping.h"
|
||||
|
||||
namespace __hwasan {
|
||||
template <unsigned X>
|
||||
__attribute__((always_inline)) static void SigTrap(uptr p) {
|
||||
#if defined(__aarch64__)
|
||||
(void)p;
|
||||
// 0x900 is added to do not interfere with the kernel use of lower values of
|
||||
// brk immediate.
|
||||
// FIXME: Add a constraint to put the pointer into x0, the same as x86 branch.
|
||||
asm("brk %0\n\t" ::"n"(0x900 + X));
|
||||
#elif defined(__x86_64__)
|
||||
// INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
|
||||
// total. The pointer is passed via rdi.
|
||||
// 0x40 is added as a safeguard, to help distinguish our trap from others and
|
||||
// to avoid 0 offsets in the command (otherwise it'll be reduced to a
|
||||
// different nop command, the three bytes one).
|
||||
asm volatile(
|
||||
"int3\n"
|
||||
"nopl %c0(%%rax)\n" ::"n"(0x40 + X),
|
||||
"D"(p));
|
||||
#else
|
||||
// FIXME: not always sigill.
|
||||
__builtin_trap();
|
||||
#endif
|
||||
// __builtin_unreachable();
|
||||
}
|
||||
|
||||
enum class ErrorAction { Abort, Recover };
|
||||
enum class AccessType { Load, Store };
|
||||
|
||||
template <ErrorAction EA, AccessType AT, unsigned LogSize>
|
||||
__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
|
||||
tag_t ptr_tag = GetTagFromPointer(p);
|
||||
uptr ptr_raw = p & ~kAddressTagMask;
|
||||
tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
|
||||
if (UNLIKELY(ptr_tag != mem_tag)) {
|
||||
SigTrap<0x20 * (EA == ErrorAction::Recover) +
|
||||
0x10 * (AT == AccessType::Store) + LogSize>(p);
|
||||
if (EA == ErrorAction::Abort)
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
template <ErrorAction EA, AccessType AT>
|
||||
__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
|
||||
uptr sz) {
|
||||
if (sz == 0)
|
||||
return;
|
||||
tag_t ptr_tag = GetTagFromPointer(p);
|
||||
uptr ptr_raw = p & ~kAddressTagMask;
|
||||
tag_t *shadow_first = (tag_t *)MemToShadow(ptr_raw);
|
||||
tag_t *shadow_last = (tag_t *)MemToShadow(ptr_raw + sz - 1);
|
||||
for (tag_t *t = shadow_first; t <= shadow_last; ++t)
|
||||
if (UNLIKELY(ptr_tag != *t)) {
|
||||
SigTrap<0x20 * (EA == ErrorAction::Recover) +
|
||||
0x10 * (AT == AccessType::Store) + 0xf>(p);
|
||||
if (EA == ErrorAction::Abort)
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
} // end namespace __hwasan
|
||||
|
||||
#endif // HWASAN_CHECKS_H
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "hwasan.h"
|
||||
#include "hwasan_dynamic_shadow.h"
|
||||
#include "hwasan_mapping.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
|
|
@ -35,12 +36,16 @@ static void UnmapFromTo(uptr from, uptr to) {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns an address aligned to 8 pages, such that one page on the left and
|
||||
// shadow_size_bytes bytes on the right of it are mapped r/o.
|
||||
// Returns an address aligned to kShadowBaseAlignment, such that
|
||||
// 2**kShadowBaseAlingment on the left and shadow_size_bytes bytes on the right
|
||||
// of it are mapped no access.
|
||||
static uptr MapDynamicShadow(uptr shadow_size_bytes) {
|
||||
const uptr granularity = GetMmapGranularity();
|
||||
const uptr alignment = granularity * SHADOW_GRANULARITY;
|
||||
const uptr left_padding = granularity;
|
||||
const uptr min_alignment = granularity << kShadowScale;
|
||||
const uptr alignment = 1ULL << kShadowBaseAlignment;
|
||||
CHECK_GE(alignment, min_alignment);
|
||||
|
||||
const uptr left_padding = 1ULL << kShadowBaseAlignment;
|
||||
const uptr shadow_size =
|
||||
RoundUpTo(shadow_size_bytes, granularity);
|
||||
const uptr map_size = shadow_size + left_padding + alignment;
|
||||
|
|
@ -58,8 +63,7 @@ static uptr MapDynamicShadow(uptr shadow_size_bytes) {
|
|||
|
||||
} // namespace __hwasan
|
||||
|
||||
#if HWASAN_PREMAP_SHADOW
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
extern "C" {
|
||||
|
||||
INTERFACE_ATTRIBUTE void __hwasan_shadow();
|
||||
|
|
@ -117,16 +121,22 @@ void __hwasan_shadow();
|
|||
|
||||
} // extern "C"
|
||||
|
||||
#endif // HWASAN_PREMAP_SHADOW
|
||||
|
||||
namespace __hwasan {
|
||||
|
||||
uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
|
||||
#if HWASAN_PREMAP_SHADOW
|
||||
if (IsPremapShadowAvailable())
|
||||
return FindPremappedShadowStart(shadow_size_bytes);
|
||||
#endif
|
||||
return MapDynamicShadow(shadow_size_bytes);
|
||||
}
|
||||
|
||||
} // namespace __hwasan
|
||||
#else
|
||||
namespace __hwasan {
|
||||
|
||||
uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
|
||||
return MapDynamicShadow(shadow_size_bytes);
|
||||
}
|
||||
|
||||
} // namespace __hwasan
|
||||
#
|
||||
#endif // SANITIZER_ANDROID
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===-- hwasan_flags.h --------------------------------------------*- C++ -*-===//
|
||||
//===-- hwasan_flags.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@
|
|||
// HWASAN_FLAG(Type, Name, DefaultValue, Description)
|
||||
// See COMMON_FLAG in sanitizer_flags.inc for more details.
|
||||
|
||||
HWASAN_FLAG(bool, verbose_threads, false,
|
||||
"inform on thread creation/destruction")
|
||||
HWASAN_FLAG(bool, tag_in_malloc, true, "")
|
||||
HWASAN_FLAG(bool, tag_in_free, true, "")
|
||||
HWASAN_FLAG(bool, retag_in_realloc, true, "")
|
||||
HWASAN_FLAG(bool, print_stats, false, "")
|
||||
HWASAN_FLAG(bool, halt_on_error, true, "")
|
||||
HWASAN_FLAG(bool, atexit, false, "")
|
||||
|
|
@ -31,3 +32,57 @@ HWASAN_FLAG(bool, disable_allocator_tagging, false, "")
|
|||
// If false, use simple increment of a thread local counter to generate new
|
||||
// tags.
|
||||
HWASAN_FLAG(bool, random_tags, true, "")
|
||||
|
||||
HWASAN_FLAG(
|
||||
int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K.
|
||||
"HWASan allocator flag. max_malloc_fill_size is the maximal amount of "
|
||||
"bytes that will be filled with malloc_fill_byte on malloc.")
|
||||
|
||||
// Rules for malloc alignment on aarch64:
|
||||
// * If the size is 16-aligned, then malloc should return 16-aligned memory.
|
||||
// * Otherwise, malloc should return 8-alignment memory.
|
||||
// So,
|
||||
// * If the size is 16-aligned, we don't need to do anything.
|
||||
// * Otherwise we don't have to obey 16-alignment, just the 8-alignment.
|
||||
// * We may want to break the 8-alignment rule to catch more buffer overflows
|
||||
// but this will break valid code in some rare cases, like this:
|
||||
// struct Foo {
|
||||
// // accessed via atomic instructions that require 8-alignment.
|
||||
// std::atomic<int64_t> atomic_stuff;
|
||||
// ...
|
||||
// char vla[1]; // the actual size of vla could be anything.
|
||||
// }
|
||||
// Which means that the safe values for malloc_align_right are 0, 8, 9,
|
||||
// and the values 1 and 2 may require changes in otherwise valid code.
|
||||
|
||||
HWASAN_FLAG(
|
||||
int, malloc_align_right, 0, // off by default
|
||||
"HWASan allocator flag. "
|
||||
"0 (default): allocations are always aligned left to 16-byte boundary; "
|
||||
"1: allocations are sometimes aligned right to 1-byte boundary (risky); "
|
||||
"2: allocations are always aligned right to 1-byte boundary (risky); "
|
||||
"8: allocations are sometimes aligned right to 8-byte boundary; "
|
||||
"9: allocations are always aligned right to 8-byte boundary."
|
||||
)
|
||||
HWASAN_FLAG(bool, free_checks_tail_magic, 1,
|
||||
"If set, free() will check the magic values "
|
||||
"to the right of the allocated object "
|
||||
"if the allocation size is not a divident of the granule size")
|
||||
HWASAN_FLAG(
|
||||
int, max_free_fill_size, 0,
|
||||
"HWASan allocator flag. max_free_fill_size is the maximal amount of "
|
||||
"bytes that will be filled with free_fill_byte during free.")
|
||||
HWASAN_FLAG(int, malloc_fill_byte, 0xbe,
|
||||
"Value used to fill the newly allocated memory.")
|
||||
HWASAN_FLAG(int, free_fill_byte, 0x55,
|
||||
"Value used to fill deallocated memory.")
|
||||
HWASAN_FLAG(int, heap_history_size, 1023,
|
||||
"The number of heap (de)allocations remembered per thread. "
|
||||
"Affects the quality of heap-related reports, but not the ability "
|
||||
"to find bugs.")
|
||||
HWASAN_FLAG(bool, export_memory_stats, true,
|
||||
"Export up-to-date memory stats through /proc")
|
||||
HWASAN_FLAG(int, stack_history_size, 1024,
|
||||
"The number of stack frames remembered per thread. "
|
||||
"Affects the quality of stack-related reports, but not the ability "
|
||||
"to find bugs.")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===-- hwasan_interceptors.cc ----------------------------------------------===//
|
||||
//===-- hwasan_interceptors.cc --------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "interception/interception.h"
|
||||
#include "hwasan.h"
|
||||
#include "hwasan_allocator.h"
|
||||
#include "hwasan_mapping.h"
|
||||
#include "hwasan_thread.h"
|
||||
#include "hwasan_poisoning.h"
|
||||
|
|
@ -44,24 +45,19 @@ using __sanitizer::atomic_load;
|
|||
using __sanitizer::atomic_store;
|
||||
using __sanitizer::atomic_uintptr_t;
|
||||
|
||||
DECLARE_REAL(SIZE_T, strlen, const char *s)
|
||||
DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen)
|
||||
DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
|
||||
DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
|
||||
|
||||
bool IsInInterceptorScope() {
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
Thread *t = GetCurrentThread();
|
||||
return t && t->InInterceptorScope();
|
||||
}
|
||||
|
||||
struct InterceptorScope {
|
||||
InterceptorScope() {
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
Thread *t = GetCurrentThread();
|
||||
if (t)
|
||||
t->EnterInterceptorScope();
|
||||
}
|
||||
~InterceptorScope() {
|
||||
HwasanThread *t = GetCurrentThread();
|
||||
Thread *t = GetCurrentThread();
|
||||
if (t)
|
||||
t->LeaveInterceptorScope();
|
||||
}
|
||||
|
|
@ -92,66 +88,24 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) {
|
|||
} while (0)
|
||||
|
||||
|
||||
|
||||
#define HWASAN_READ_RANGE(ctx, offset, size) \
|
||||
CHECK_UNPOISONED(offset, size)
|
||||
#define HWASAN_WRITE_RANGE(ctx, offset, size) \
|
||||
CHECK_UNPOISONED(offset, size)
|
||||
|
||||
|
||||
|
||||
// Check that [x, x+n) range is unpoisoned.
|
||||
#define CHECK_UNPOISONED_0(x, n) \
|
||||
do { \
|
||||
sptr __offset = __hwasan_test_shadow(x, n); \
|
||||
if (__hwasan::IsInSymbolizer()) break; \
|
||||
if (__offset >= 0) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
(void)sp; \
|
||||
ReportInvalidAccessInsideAddressRange(__func__, x, n, __offset); \
|
||||
__hwasan::PrintWarning(pc, bp); \
|
||||
if (__hwasan::flags()->halt_on_error) { \
|
||||
Printf("Exiting\n"); \
|
||||
Die(); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Check that [x, x+n) range is unpoisoned unless we are in a nested
|
||||
// interceptor.
|
||||
#define CHECK_UNPOISONED(x, n) \
|
||||
do { \
|
||||
if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n) \
|
||||
CHECK_UNPOISONED((x), \
|
||||
common_flags()->strict_string_checks ? (len) + 1 : (n) )
|
||||
|
||||
|
||||
INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
|
||||
int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
CHECK_NE(memptr, 0);
|
||||
int res = hwasan_posix_memalign(memptr, alignment, size, &stack);
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
|
||||
INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) {
|
||||
void * __sanitizer_memalign(uptr alignment, uptr size) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
return hwasan_memalign(alignment, size, &stack);
|
||||
}
|
||||
#define HWASAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
|
||||
#else
|
||||
#define HWASAN_MAYBE_INTERCEPT_MEMALIGN
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) {
|
||||
void * __sanitizer_aligned_alloc(uptr alignment, uptr size) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
return hwasan_aligned_alloc(alignment, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) {
|
||||
void * __sanitizer___libc_memalign(uptr alignment, uptr size) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
void *ptr = hwasan_memalign(alignment, size, &stack);
|
||||
if (ptr)
|
||||
|
|
@ -159,80 +113,47 @@ INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) {
|
|||
return ptr;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, valloc, SIZE_T size) {
|
||||
void * __sanitizer_valloc(uptr size) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
return hwasan_valloc(size, &stack);
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
|
||||
INTERCEPTOR(void *, pvalloc, SIZE_T size) {
|
||||
void * __sanitizer_pvalloc(uptr size) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
return hwasan_pvalloc(size, &stack);
|
||||
}
|
||||
#define HWASAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
|
||||
#else
|
||||
#define HWASAN_MAYBE_INTERCEPT_PVALLOC
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(void, free, void *ptr) {
|
||||
void __sanitizer_free(void *ptr) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
|
||||
HwasanDeallocate(&stack, ptr);
|
||||
hwasan_free(ptr, &stack);
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
|
||||
INTERCEPTOR(void, cfree, void *ptr) {
|
||||
void __sanitizer_cfree(void *ptr) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
|
||||
HwasanDeallocate(&stack, ptr);
|
||||
hwasan_free(ptr, &stack);
|
||||
}
|
||||
#define HWASAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
|
||||
#else
|
||||
#define HWASAN_MAYBE_INTERCEPT_CFREE
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
|
||||
uptr __sanitizer_malloc_usable_size(const void *ptr) {
|
||||
return __sanitizer_get_allocated_size(ptr);
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
|
||||
// This function actually returns a struct by value, but we can't unpoison a
|
||||
// temporary! The following is equivalent on all supported platforms but
|
||||
// aarch64 (which uses a different register for sret value). We have a test
|
||||
// to confirm that.
|
||||
INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) {
|
||||
#ifdef __aarch64__
|
||||
uptr r8;
|
||||
asm volatile("mov %0,x8" : "=r" (r8));
|
||||
sret = reinterpret_cast<__sanitizer_mallinfo*>(r8);
|
||||
#endif
|
||||
REAL(memset)(sret, 0, sizeof(*sret));
|
||||
struct __sanitizer_struct_mallinfo __sanitizer_mallinfo() {
|
||||
__sanitizer_struct_mallinfo sret;
|
||||
internal_memset(&sret, 0, sizeof(sret));
|
||||
return sret;
|
||||
}
|
||||
#define HWASAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
|
||||
#else
|
||||
#define HWASAN_MAYBE_INTERCEPT_MALLINFO
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
|
||||
INTERCEPTOR(int, mallopt, int cmd, int value) {
|
||||
return -1;
|
||||
int __sanitizer_mallopt(int cmd, int value) {
|
||||
return 0;
|
||||
}
|
||||
#define HWASAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
|
||||
#else
|
||||
#define HWASAN_MAYBE_INTERCEPT_MALLOPT
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
|
||||
INTERCEPTOR(void, malloc_stats, void) {
|
||||
void __sanitizer_malloc_stats(void) {
|
||||
// FIXME: implement, but don't call REAL(malloc_stats)!
|
||||
}
|
||||
#define HWASAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats)
|
||||
#else
|
||||
#define HWASAN_MAYBE_INTERCEPT_MALLOC_STATS
|
||||
#endif
|
||||
|
||||
|
||||
INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
|
||||
void * __sanitizer_calloc(uptr nmemb, uptr size) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
if (UNLIKELY(!hwasan_inited))
|
||||
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
|
||||
|
|
@ -240,7 +161,7 @@ INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
|
|||
return hwasan_calloc(nmemb, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
|
||||
void * __sanitizer_realloc(void *ptr, uptr size) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
|
||||
uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
|
||||
|
|
@ -258,7 +179,7 @@ INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
|
|||
return hwasan_realloc(ptr, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, malloc, SIZE_T size) {
|
||||
void * __sanitizer_malloc(uptr size) {
|
||||
GET_MALLOC_STACK_TRACE;
|
||||
if (UNLIKELY(!hwasan_init_is_running))
|
||||
ENSURE_HWASAN_INITED();
|
||||
|
|
@ -268,48 +189,44 @@ INTERCEPTOR(void *, malloc, SIZE_T size) {
|
|||
return hwasan_malloc(size, &stack);
|
||||
}
|
||||
|
||||
template <class Mmap>
|
||||
static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T sz, int prot,
|
||||
int flags, int fd, OFF64_T off) {
|
||||
if (addr && !MEM_IS_APP(addr)) {
|
||||
if (flags & map_fixed) {
|
||||
errno = errno_EINVAL;
|
||||
return (void *)-1;
|
||||
} else {
|
||||
addr = nullptr;
|
||||
}
|
||||
}
|
||||
return real_mmap(addr, sz, prot, flags, fd, off);
|
||||
}
|
||||
#if HWASAN_WITH_INTERCEPTORS
|
||||
#define INTERCEPTOR_ALIAS(RET, FN, ARGS...) \
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE RET WRAP(FN)(ARGS) \
|
||||
ALIAS("__sanitizer_" #FN); \
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE RET FN( \
|
||||
ARGS) ALIAS("__sanitizer_" #FN)
|
||||
|
||||
extern "C" int pthread_attr_init(void *attr);
|
||||
extern "C" int pthread_attr_destroy(void *attr);
|
||||
INTERCEPTOR_ALIAS(int, posix_memalign, void **memptr, SIZE_T alignment,
|
||||
SIZE_T size);
|
||||
INTERCEPTOR_ALIAS(void *, aligned_alloc, SIZE_T alignment, SIZE_T size);
|
||||
INTERCEPTOR_ALIAS(void *, __libc_memalign, SIZE_T alignment, SIZE_T size);
|
||||
INTERCEPTOR_ALIAS(void *, valloc, SIZE_T size);
|
||||
INTERCEPTOR_ALIAS(void, free, void *ptr);
|
||||
INTERCEPTOR_ALIAS(uptr, malloc_usable_size, const void *ptr);
|
||||
INTERCEPTOR_ALIAS(void *, calloc, SIZE_T nmemb, SIZE_T size);
|
||||
INTERCEPTOR_ALIAS(void *, realloc, void *ptr, SIZE_T size);
|
||||
INTERCEPTOR_ALIAS(void *, malloc, SIZE_T size);
|
||||
|
||||
static void *HwasanThreadStartFunc(void *arg) {
|
||||
HwasanThread *t = (HwasanThread *)arg;
|
||||
SetCurrentThread(t);
|
||||
return t->ThreadStart();
|
||||
}
|
||||
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
|
||||
INTERCEPTOR_ALIAS(void *, memalign, SIZE_T alignment, SIZE_T size);
|
||||
INTERCEPTOR_ALIAS(void *, pvalloc, SIZE_T size);
|
||||
INTERCEPTOR_ALIAS(void, cfree, void *ptr);
|
||||
INTERCEPTOR_ALIAS(__sanitizer_struct_mallinfo, mallinfo);
|
||||
INTERCEPTOR_ALIAS(int, mallopt, int cmd, int value);
|
||||
INTERCEPTOR_ALIAS(void, malloc_stats, void);
|
||||
#endif
|
||||
#endif // HWASAN_WITH_INTERCEPTORS
|
||||
|
||||
INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
|
||||
void * param) {
|
||||
ENSURE_HWASAN_INITED(); // for GetTlsSize()
|
||||
__sanitizer_pthread_attr_t myattr;
|
||||
if (!attr) {
|
||||
pthread_attr_init(&myattr);
|
||||
attr = &myattr;
|
||||
}
|
||||
|
||||
AdjustStackSize(attr);
|
||||
|
||||
HwasanThread *t = HwasanThread::Create(callback, param);
|
||||
|
||||
int res = REAL(pthread_create)(th, attr, HwasanThreadStartFunc, t);
|
||||
|
||||
if (attr == &myattr)
|
||||
pthread_attr_destroy(&myattr);
|
||||
#if HWASAN_WITH_INTERCEPTORS && !defined(__aarch64__)
|
||||
INTERCEPTOR(int, pthread_create, void *th, void *attr,
|
||||
void *(*callback)(void *), void *param) {
|
||||
ScopedTaggingDisabler disabler;
|
||||
int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
|
||||
callback, param);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void BeforeFork() {
|
||||
StackDepotLockAll();
|
||||
|
|
@ -341,137 +258,21 @@ int OnExit() {
|
|||
|
||||
} // namespace __hwasan
|
||||
|
||||
// A version of CHECK_UNPOISONED using a saved scope value. Used in common
|
||||
// interceptors.
|
||||
#define CHECK_UNPOISONED_CTX(ctx, x, n) \
|
||||
do { \
|
||||
if (!((HwasanInterceptorContext *)ctx)->in_interceptor_scope) \
|
||||
CHECK_UNPOISONED_0(x, n); \
|
||||
} while (0)
|
||||
|
||||
#define HWASAN_INTERCEPT_FUNC(name) \
|
||||
do { \
|
||||
if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
|
||||
VReport(1, "HWAddressSanitizer: failed to intercept '" #name "'\n"); \
|
||||
} while (0)
|
||||
|
||||
#define HWASAN_INTERCEPT_FUNC_VER(name, ver) \
|
||||
do { \
|
||||
if ((!INTERCEPT_FUNCTION_VER(name, ver) || !REAL(name))) \
|
||||
VReport( \
|
||||
1, "HWAddressSanitizer: failed to intercept '" #name "@@" #ver "'\n"); \
|
||||
} while (0)
|
||||
|
||||
#define COMMON_INTERCEPT_FUNCTION(name) HWASAN_INTERCEPT_FUNC(name)
|
||||
#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
|
||||
HWASAN_INTERCEPT_FUNC_VER(name, ver)
|
||||
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
|
||||
CHECK_UNPOISONED_CTX(ctx, ptr, size)
|
||||
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
|
||||
CHECK_UNPOISONED_CTX(ctx, ptr, size)
|
||||
#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \
|
||||
HWASAN_WRITE_RANGE(ctx, ptr, size)
|
||||
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
|
||||
if (hwasan_init_is_running) return REAL(func)(__VA_ARGS__); \
|
||||
ENSURE_HWASAN_INITED(); \
|
||||
HwasanInterceptorContext hwasan_ctx = {IsInInterceptorScope()}; \
|
||||
ctx = (void *)&hwasan_ctx; \
|
||||
(void)ctx; \
|
||||
InterceptorScope interceptor_scope;
|
||||
#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
|
||||
do { \
|
||||
} while (false) // FIXME
|
||||
#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
|
||||
do { \
|
||||
} while (false) // FIXME
|
||||
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
|
||||
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
|
||||
|
||||
#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
|
||||
if (HwasanThread *t = GetCurrentThread()) { \
|
||||
*begin = t->tls_begin(); \
|
||||
*end = t->tls_end(); \
|
||||
} else { \
|
||||
*begin = *end = 0; \
|
||||
}
|
||||
|
||||
#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \
|
||||
{ \
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size); \
|
||||
if (common_flags()->intercept_intrin && \
|
||||
MEM_IS_APP(GetAddressFromPointer(dst))) \
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
|
||||
return REAL(memset)(dst, v, size); \
|
||||
}
|
||||
|
||||
#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, fd, \
|
||||
offset) \
|
||||
do { \
|
||||
return mmap_interceptor(REAL(mmap), addr, length, prot, flags, fd, \
|
||||
offset); \
|
||||
} while (false)
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
||||
#include "sanitizer_common/sanitizer_common_interceptors.inc"
|
||||
#include "sanitizer_common/sanitizer_signal_interceptors.inc"
|
||||
|
||||
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
|
||||
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
|
||||
do { \
|
||||
(void)(p); \
|
||||
(void)(s); \
|
||||
} while (false)
|
||||
#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
|
||||
do { \
|
||||
(void)(p); \
|
||||
(void)(s); \
|
||||
} while (false)
|
||||
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
|
||||
do { \
|
||||
(void)(p); \
|
||||
(void)(s); \
|
||||
} while (false)
|
||||
#include "sanitizer_common/sanitizer_common_syscalls.inc"
|
||||
#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
|
||||
|
||||
|
||||
|
||||
namespace __hwasan {
|
||||
|
||||
void InitializeInterceptors() {
|
||||
static int inited = 0;
|
||||
CHECK_EQ(inited, 0);
|
||||
InitializeCommonInterceptors();
|
||||
InitializeSignalInterceptors();
|
||||
|
||||
INTERCEPT_FUNCTION(posix_memalign);
|
||||
HWASAN_MAYBE_INTERCEPT_MEMALIGN;
|
||||
INTERCEPT_FUNCTION(__libc_memalign);
|
||||
INTERCEPT_FUNCTION(valloc);
|
||||
HWASAN_MAYBE_INTERCEPT_PVALLOC;
|
||||
INTERCEPT_FUNCTION(malloc);
|
||||
INTERCEPT_FUNCTION(calloc);
|
||||
INTERCEPT_FUNCTION(fork);
|
||||
|
||||
#if HWASAN_WITH_INTERCEPTORS
|
||||
#if !defined(__aarch64__)
|
||||
INTERCEPT_FUNCTION(pthread_create);
|
||||
#endif
|
||||
INTERCEPT_FUNCTION(realloc);
|
||||
INTERCEPT_FUNCTION(free);
|
||||
HWASAN_MAYBE_INTERCEPT_CFREE;
|
||||
INTERCEPT_FUNCTION(malloc_usable_size);
|
||||
HWASAN_MAYBE_INTERCEPT_MALLINFO;
|
||||
HWASAN_MAYBE_INTERCEPT_MALLOPT;
|
||||
HWASAN_MAYBE_INTERCEPT_MALLOC_STATS;
|
||||
INTERCEPT_FUNCTION(pthread_create);
|
||||
INTERCEPT_FUNCTION(fork);
|
||||
#endif
|
||||
|
||||
inited = 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===-- hwasan_interface_internal.h -------------------------------*- C++ -*-===//
|
||||
//===-- hwasan_interface_internal.h -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -16,9 +16,13 @@
|
|||
#define HWASAN_INTERFACE_INTERNAL_H
|
||||
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __hwasan_shadow_init();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __hwasan_init();
|
||||
|
||||
|
|
@ -32,6 +36,9 @@ using __sanitizer::u32;
|
|||
using __sanitizer::u16;
|
||||
using __sanitizer::u8;
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __hwasan_init_frames(uptr, uptr);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
extern uptr __hwasan_shadow_memory_dynamic_address;
|
||||
|
||||
|
|
@ -90,6 +97,9 @@ void __hwasan_store16_noabort(uptr);
|
|||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __hwasan_tag_memory(uptr p, u8 tag, uptr sz);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __hwasan_tag_pointer(uptr p, u8 tag);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
u8 __hwasan_generate_tag();
|
||||
|
||||
|
|
@ -104,6 +114,9 @@ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
|||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __hwasan_print_shadow(const void *x, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __hwasan_handle_longjmp(const void *sp_dst);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
u16 __sanitizer_unaligned_load16(const uu16 *p);
|
||||
|
||||
|
|
@ -128,6 +141,66 @@ void __hwasan_enable_allocator_tagging();
|
|||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __hwasan_disable_allocator_tagging();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __hwasan_thread_enter();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __hwasan_thread_exit();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __hwasan_print_memory_usage();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void * __sanitizer_memalign(uptr alignment, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void * __sanitizer_aligned_alloc(uptr alignment, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void * __sanitizer___libc_memalign(uptr alignment, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void * __sanitizer_valloc(uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void * __sanitizer_pvalloc(uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_free(void *ptr);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_cfree(void *ptr);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __sanitizer_malloc_usable_size(const void *ptr);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
__hwasan::__sanitizer_struct_mallinfo __sanitizer_mallinfo();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
int __sanitizer_mallopt(int cmd, int value);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_malloc_stats(void);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void * __sanitizer_calloc(uptr nmemb, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void * __sanitizer_realloc(void *ptr, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void * __sanitizer_malloc(uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__hwasan_memcpy(void *dst, const void *src, uptr size);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__hwasan_memset(void *s, int c, uptr n);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__hwasan_memmove(void *dest, const void *src, uptr n);
|
||||
} // extern "C"
|
||||
|
||||
#endif // HWASAN_INTERFACE_INTERNAL_H
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@
|
|||
#include "hwasan_mapping.h"
|
||||
#include "hwasan_report.h"
|
||||
#include "hwasan_thread.h"
|
||||
#include "hwasan_thread_list.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#include <pthread.h>
|
||||
|
|
@ -37,6 +39,11 @@
|
|||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
|
||||
#if HWASAN_WITH_INTERCEPTORS && !SANITIZER_ANDROID
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
THREADLOCAL uptr __hwasan_tls;
|
||||
#endif
|
||||
|
||||
namespace __hwasan {
|
||||
|
||||
static void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
|
||||
|
|
@ -51,8 +58,6 @@ static void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
|
|||
size);
|
||||
Abort();
|
||||
}
|
||||
if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size);
|
||||
if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
|
||||
}
|
||||
|
||||
static void ProtectGap(uptr addr, uptr size) {
|
||||
|
|
@ -103,55 +108,31 @@ static void PrintAddressSpaceLayout() {
|
|||
else
|
||||
CHECK_EQ(kHighShadowEnd + 1, kHighMemStart);
|
||||
PrintRange(kHighShadowStart, kHighShadowEnd, "HighShadow");
|
||||
if (SHADOW_OFFSET) {
|
||||
if (kLowShadowEnd + 1 < kHighShadowStart)
|
||||
PrintRange(kLowShadowEnd + 1, kHighShadowStart - 1, "ShadowGap");
|
||||
else
|
||||
CHECK_EQ(kLowMemEnd + 1, kHighShadowStart);
|
||||
PrintRange(kLowShadowStart, kLowShadowEnd, "LowShadow");
|
||||
if (kLowMemEnd + 1 < kLowShadowStart)
|
||||
PrintRange(kLowMemEnd + 1, kLowShadowStart - 1, "ShadowGap");
|
||||
else
|
||||
CHECK_EQ(kLowMemEnd + 1, kLowShadowStart);
|
||||
PrintRange(kLowMemStart, kLowMemEnd, "LowMem");
|
||||
CHECK_EQ(0, kLowMemStart);
|
||||
} else {
|
||||
if (kLowMemEnd + 1 < kHighShadowStart)
|
||||
PrintRange(kLowMemEnd + 1, kHighShadowStart - 1, "ShadowGap");
|
||||
else
|
||||
CHECK_EQ(kLowMemEnd + 1, kHighShadowStart);
|
||||
PrintRange(kLowMemStart, kLowMemEnd, "LowMem");
|
||||
CHECK_EQ(kLowShadowEnd + 1, kLowMemStart);
|
||||
PrintRange(kLowShadowStart, kLowShadowEnd, "LowShadow");
|
||||
PrintRange(0, kLowShadowStart - 1, "ShadowGap");
|
||||
}
|
||||
if (kLowShadowEnd + 1 < kHighShadowStart)
|
||||
PrintRange(kLowShadowEnd + 1, kHighShadowStart - 1, "ShadowGap");
|
||||
else
|
||||
CHECK_EQ(kLowMemEnd + 1, kHighShadowStart);
|
||||
PrintRange(kLowShadowStart, kLowShadowEnd, "LowShadow");
|
||||
if (kLowMemEnd + 1 < kLowShadowStart)
|
||||
PrintRange(kLowMemEnd + 1, kLowShadowStart - 1, "ShadowGap");
|
||||
else
|
||||
CHECK_EQ(kLowMemEnd + 1, kLowShadowStart);
|
||||
PrintRange(kLowMemStart, kLowMemEnd, "LowMem");
|
||||
CHECK_EQ(0, kLowMemStart);
|
||||
}
|
||||
|
||||
static uptr GetHighMemEnd() {
|
||||
// HighMem covers the upper part of the address space.
|
||||
uptr max_address = GetMaxUserVirtualAddress();
|
||||
if (SHADOW_OFFSET)
|
||||
// Adjust max address to make sure that kHighMemEnd and kHighMemStart are
|
||||
// properly aligned:
|
||||
max_address |= SHADOW_GRANULARITY * GetMmapGranularity() - 1;
|
||||
// Adjust max address to make sure that kHighMemEnd and kHighMemStart are
|
||||
// properly aligned:
|
||||
max_address |= (GetMmapGranularity() << kShadowScale) - 1;
|
||||
return max_address;
|
||||
}
|
||||
|
||||
static void InitializeShadowBaseAddress(uptr shadow_size_bytes) {
|
||||
// Set the shadow memory address to uninitialized.
|
||||
__hwasan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
|
||||
uptr shadow_start = SHADOW_OFFSET;
|
||||
// Detect if a dynamic shadow address must be used and find the available
|
||||
// location when necessary. When dynamic address is used, the macro
|
||||
// kLowShadowBeg expands to __hwasan_shadow_memory_dynamic_address which
|
||||
// was just set to kDefaultShadowSentinel.
|
||||
if (shadow_start == kDefaultShadowSentinel) {
|
||||
__hwasan_shadow_memory_dynamic_address = 0;
|
||||
CHECK_EQ(0, SHADOW_OFFSET);
|
||||
shadow_start = FindDynamicShadowStart(shadow_size_bytes);
|
||||
}
|
||||
// Update the shadow memory address (potentially) used by instrumentation.
|
||||
__hwasan_shadow_memory_dynamic_address = shadow_start;
|
||||
__hwasan_shadow_memory_dynamic_address =
|
||||
FindDynamicShadowStart(shadow_size_bytes);
|
||||
}
|
||||
|
||||
bool InitShadow() {
|
||||
|
|
@ -159,29 +140,23 @@ bool InitShadow() {
|
|||
kHighMemEnd = GetHighMemEnd();
|
||||
|
||||
// Determine shadow memory base offset.
|
||||
InitializeShadowBaseAddress(MEM_TO_SHADOW_SIZE(kHighMemEnd));
|
||||
InitializeShadowBaseAddress(MemToShadowSize(kHighMemEnd));
|
||||
|
||||
// Place the low memory first.
|
||||
if (SHADOW_OFFSET) {
|
||||
kLowMemEnd = SHADOW_OFFSET - 1;
|
||||
kLowMemStart = 0;
|
||||
} else {
|
||||
// LowMem covers as much of the first 4GB as possible.
|
||||
kLowMemEnd = (1UL << 32) - 1;
|
||||
kLowMemStart = MEM_TO_SHADOW(kLowMemEnd) + 1;
|
||||
}
|
||||
kLowMemEnd = __hwasan_shadow_memory_dynamic_address - 1;
|
||||
kLowMemStart = 0;
|
||||
|
||||
// Define the low shadow based on the already placed low memory.
|
||||
kLowShadowEnd = MEM_TO_SHADOW(kLowMemEnd);
|
||||
kLowShadowStart = SHADOW_OFFSET ? SHADOW_OFFSET : MEM_TO_SHADOW(kLowMemStart);
|
||||
kLowShadowEnd = MemToShadow(kLowMemEnd);
|
||||
kLowShadowStart = __hwasan_shadow_memory_dynamic_address;
|
||||
|
||||
// High shadow takes whatever memory is left up there (making sure it is not
|
||||
// interfering with low memory in the fixed case).
|
||||
kHighShadowEnd = MEM_TO_SHADOW(kHighMemEnd);
|
||||
kHighShadowStart = Max(kLowMemEnd, MEM_TO_SHADOW(kHighShadowEnd)) + 1;
|
||||
kHighShadowEnd = MemToShadow(kHighMemEnd);
|
||||
kHighShadowStart = Max(kLowMemEnd, MemToShadow(kHighShadowEnd)) + 1;
|
||||
|
||||
// High memory starts where allocated shadow allows.
|
||||
kHighMemStart = SHADOW_TO_MEM(kHighShadowStart);
|
||||
kHighMemStart = ShadowToMem(kHighShadowStart);
|
||||
|
||||
// Check the sanity of the defined memory ranges (there might be gaps).
|
||||
CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0);
|
||||
|
|
@ -190,10 +165,7 @@ bool InitShadow() {
|
|||
CHECK_GT(kHighShadowStart, kLowMemEnd);
|
||||
CHECK_GT(kLowMemEnd, kLowMemStart);
|
||||
CHECK_GT(kLowShadowEnd, kLowShadowStart);
|
||||
if (SHADOW_OFFSET)
|
||||
CHECK_GT(kLowShadowStart, kLowMemEnd);
|
||||
else
|
||||
CHECK_GT(kLowMemEnd, kLowShadowStart);
|
||||
CHECK_GT(kLowShadowStart, kLowMemEnd);
|
||||
|
||||
if (Verbosity())
|
||||
PrintAddressSpaceLayout();
|
||||
|
|
@ -204,21 +176,43 @@ bool InitShadow() {
|
|||
|
||||
// Protect all the gaps.
|
||||
ProtectGap(0, Min(kLowMemStart, kLowShadowStart));
|
||||
if (SHADOW_OFFSET) {
|
||||
if (kLowMemEnd + 1 < kLowShadowStart)
|
||||
ProtectGap(kLowMemEnd + 1, kLowShadowStart - kLowMemEnd - 1);
|
||||
if (kLowShadowEnd + 1 < kHighShadowStart)
|
||||
ProtectGap(kLowShadowEnd + 1, kHighShadowStart - kLowShadowEnd - 1);
|
||||
} else {
|
||||
if (kLowMemEnd + 1 < kHighShadowStart)
|
||||
ProtectGap(kLowMemEnd + 1, kHighShadowStart - kLowMemEnd - 1);
|
||||
}
|
||||
if (kLowMemEnd + 1 < kLowShadowStart)
|
||||
ProtectGap(kLowMemEnd + 1, kLowShadowStart - kLowMemEnd - 1);
|
||||
if (kLowShadowEnd + 1 < kHighShadowStart)
|
||||
ProtectGap(kLowShadowEnd + 1, kHighShadowStart - kLowShadowEnd - 1);
|
||||
if (kHighShadowEnd + 1 < kHighMemStart)
|
||||
ProtectGap(kHighShadowEnd + 1, kHighMemStart - kHighShadowEnd - 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitThreads() {
|
||||
CHECK(__hwasan_shadow_memory_dynamic_address);
|
||||
uptr guard_page_size = GetMmapGranularity();
|
||||
uptr thread_space_start =
|
||||
__hwasan_shadow_memory_dynamic_address - (1ULL << kShadowBaseAlignment);
|
||||
uptr thread_space_end =
|
||||
__hwasan_shadow_memory_dynamic_address - guard_page_size;
|
||||
ReserveShadowMemoryRange(thread_space_start, thread_space_end - 1,
|
||||
"hwasan threads");
|
||||
ProtectGap(thread_space_end,
|
||||
__hwasan_shadow_memory_dynamic_address - thread_space_end);
|
||||
InitThreadList(thread_space_start, thread_space_end - thread_space_start);
|
||||
}
|
||||
|
||||
static void MadviseShadowRegion(uptr beg, uptr end) {
|
||||
uptr size = end - beg + 1;
|
||||
if (common_flags()->no_huge_pages_for_shadow)
|
||||
NoHugePagesInRegion(beg, size);
|
||||
if (common_flags()->use_madv_dontdump)
|
||||
DontDumpShadowMemory(beg, size);
|
||||
}
|
||||
|
||||
void MadviseShadow() {
|
||||
MadviseShadowRegion(kLowShadowStart, kLowShadowEnd);
|
||||
MadviseShadowRegion(kHighShadowStart, kHighShadowEnd);
|
||||
}
|
||||
|
||||
bool MemIsApp(uptr p) {
|
||||
CHECK(GetTagFromPointer(p) == 0);
|
||||
return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd);
|
||||
|
|
@ -240,37 +234,81 @@ void InstallAtExitHandler() {
|
|||
|
||||
// ---------------------- TSD ---------------- {{{1
|
||||
|
||||
extern "C" void __hwasan_thread_enter() {
|
||||
hwasanThreadList().CreateCurrentThread();
|
||||
}
|
||||
|
||||
extern "C" void __hwasan_thread_exit() {
|
||||
Thread *t = GetCurrentThread();
|
||||
// Make sure that signal handler can not see a stale current thread pointer.
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
if (t)
|
||||
hwasanThreadList().ReleaseThread(t);
|
||||
}
|
||||
|
||||
#if HWASAN_WITH_INTERCEPTORS
|
||||
static pthread_key_t tsd_key;
|
||||
static bool tsd_key_inited = false;
|
||||
|
||||
void HwasanTSDInit(void (*destructor)(void *tsd)) {
|
||||
CHECK(!tsd_key_inited);
|
||||
tsd_key_inited = true;
|
||||
CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
|
||||
}
|
||||
|
||||
HwasanThread *GetCurrentThread() {
|
||||
return (HwasanThread*)pthread_getspecific(tsd_key);
|
||||
}
|
||||
|
||||
void SetCurrentThread(HwasanThread *t) {
|
||||
// Make sure that HwasanTSDDtor gets called at the end.
|
||||
CHECK(tsd_key_inited);
|
||||
// Make sure we do not reset the current HwasanThread.
|
||||
CHECK_EQ(0, pthread_getspecific(tsd_key));
|
||||
pthread_setspecific(tsd_key, (void *)t);
|
||||
void HwasanTSDThreadInit() {
|
||||
if (tsd_key_inited)
|
||||
CHECK_EQ(0, pthread_setspecific(tsd_key,
|
||||
(void *)GetPthreadDestructorIterations()));
|
||||
}
|
||||
|
||||
void HwasanTSDDtor(void *tsd) {
|
||||
HwasanThread *t = (HwasanThread*)tsd;
|
||||
if (t->destructor_iterations_ > 1) {
|
||||
t->destructor_iterations_--;
|
||||
CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
|
||||
uptr iterations = (uptr)tsd;
|
||||
if (iterations > 1) {
|
||||
CHECK_EQ(0, pthread_setspecific(tsd_key, (void *)(iterations - 1)));
|
||||
return;
|
||||
}
|
||||
// Make sure that signal handler can not see a stale current thread pointer.
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
HwasanThread::TSDDtor(tsd);
|
||||
__hwasan_thread_exit();
|
||||
}
|
||||
|
||||
void HwasanTSDInit() {
|
||||
CHECK(!tsd_key_inited);
|
||||
tsd_key_inited = true;
|
||||
CHECK_EQ(0, pthread_key_create(&tsd_key, HwasanTSDDtor));
|
||||
}
|
||||
#else
|
||||
void HwasanTSDInit() {}
|
||||
void HwasanTSDThreadInit() {}
|
||||
#endif
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
uptr *GetCurrentThreadLongPtr() {
|
||||
return (uptr *)get_android_tls_ptr();
|
||||
}
|
||||
#else
|
||||
uptr *GetCurrentThreadLongPtr() {
|
||||
return &__hwasan_tls;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
void AndroidTestTlsSlot() {
|
||||
uptr kMagicValue = 0x010203040A0B0C0D;
|
||||
*(uptr *)get_android_tls_ptr() = kMagicValue;
|
||||
dlerror();
|
||||
if (*(uptr *)get_android_tls_ptr() != kMagicValue) {
|
||||
Printf(
|
||||
"ERROR: Incompatible version of Android: TLS_SLOT_SANITIZER(6) is used "
|
||||
"for dlerror().\n");
|
||||
Die();
|
||||
}
|
||||
}
|
||||
#else
|
||||
void AndroidTestTlsSlot() {}
|
||||
#endif
|
||||
|
||||
Thread *GetCurrentThread() {
|
||||
uptr *ThreadLong = GetCurrentThreadLongPtr();
|
||||
#if HWASAN_WITH_INTERCEPTORS
|
||||
if (!*ThreadLong)
|
||||
__hwasan_thread_enter();
|
||||
#endif
|
||||
auto *R = (StackAllocationsRingBuffer *)ThreadLong;
|
||||
return hwasanThreadList().GetThreadByBufferAddress((uptr)(R->Next()));
|
||||
}
|
||||
|
||||
struct AccessInfo {
|
||||
|
|
@ -340,14 +378,13 @@ static bool HwasanOnSIGTRAP(int signo, siginfo_t *info, ucontext_t *uc) {
|
|||
BufferedStackTrace *stack = stack_buffer.data();
|
||||
stack->Reset();
|
||||
SignalContext sig{info, uc};
|
||||
GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, uc,
|
||||
common_flags()->fast_unwind_on_fatal);
|
||||
|
||||
ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store);
|
||||
GetStackTrace(stack, kStackTraceMax, StackTrace::GetNextInstructionPc(sig.pc),
|
||||
sig.bp, uc, common_flags()->fast_unwind_on_fatal);
|
||||
|
||||
++hwasan_report_count;
|
||||
if (flags()->halt_on_error || !ai.recover)
|
||||
Die();
|
||||
|
||||
bool fatal = flags()->halt_on_error || !ai.recover;
|
||||
ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store, fatal);
|
||||
|
||||
#if defined(__aarch64__)
|
||||
uc->uc_mcontext.pc += 4;
|
||||
|
|
@ -360,8 +397,8 @@ static bool HwasanOnSIGTRAP(int signo, siginfo_t *info, ucontext_t *uc) {
|
|||
|
||||
static void OnStackUnwind(const SignalContext &sig, const void *,
|
||||
BufferedStackTrace *stack) {
|
||||
GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context,
|
||||
common_flags()->fast_unwind_on_fatal);
|
||||
GetStackTrace(stack, kStackTraceMax, StackTrace::GetNextInstructionPc(sig.pc),
|
||||
sig.bp, sig.context, common_flags()->fast_unwind_on_fatal);
|
||||
}
|
||||
|
||||
void HwasanOnDeadlySignal(int signo, void *info, void *context) {
|
||||
|
|
|
|||
|
|
@ -16,68 +16,41 @@
|
|||
#define HWASAN_MAPPING_H
|
||||
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include "hwasan_interface_internal.h"
|
||||
|
||||
// Typical mapping on Linux/x86_64 with fixed shadow mapping:
|
||||
// || [0x080000000000, 0x7fffffffffff] || HighMem ||
|
||||
// || [0x008000000000, 0x07ffffffffff] || HighShadow ||
|
||||
// || [0x000100000000, 0x007fffffffff] || ShadowGap ||
|
||||
// || [0x000010000000, 0x0000ffffffff] || LowMem ||
|
||||
// || [0x000001000000, 0x00000fffffff] || LowShadow ||
|
||||
// || [0x000000000000, 0x000000ffffff] || ShadowGap ||
|
||||
//
|
||||
// and with dynamic shadow mapped at [0x770d59f40000, 0x7f0d59f40000]:
|
||||
// Typical mapping on Linux/x86_64:
|
||||
// with dynamic shadow mapped at [0x770d59f40000, 0x7f0d59f40000]:
|
||||
// || [0x7f0d59f40000, 0x7fffffffffff] || HighMem ||
|
||||
// || [0x7efe2f934000, 0x7f0d59f3ffff] || HighShadow ||
|
||||
// || [0x7e7e2f934000, 0x7efe2f933fff] || ShadowGap ||
|
||||
// || [0x770d59f40000, 0x7e7e2f933fff] || LowShadow ||
|
||||
// || [0x000000000000, 0x770d59f3ffff] || LowMem ||
|
||||
|
||||
// Typical mapping on Android/AArch64 (39-bit VMA):
|
||||
// || [0x001000000000, 0x007fffffffff] || HighMem ||
|
||||
// || [0x000800000000, 0x000fffffffff] || ShadowGap ||
|
||||
// || [0x000100000000, 0x0007ffffffff] || HighShadow ||
|
||||
// || [0x000010000000, 0x0000ffffffff] || LowMem ||
|
||||
// || [0x000001000000, 0x00000fffffff] || LowShadow ||
|
||||
// || [0x000000000000, 0x000000ffffff] || ShadowGap ||
|
||||
//
|
||||
// and with dynamic shadow mapped: [0x007477480000, 0x007c77480000]:
|
||||
// Typical mapping on Android/AArch64
|
||||
// with dynamic shadow mapped: [0x007477480000, 0x007c77480000]:
|
||||
// || [0x007c77480000, 0x007fffffffff] || HighMem ||
|
||||
// || [0x007c3ebc8000, 0x007c7747ffff] || HighShadow ||
|
||||
// || [0x007bbebc8000, 0x007c3ebc7fff] || ShadowGap ||
|
||||
// || [0x007477480000, 0x007bbebc7fff] || LowShadow ||
|
||||
// || [0x000000000000, 0x00747747ffff] || LowMem ||
|
||||
|
||||
static constexpr __sanitizer::u64 kDefaultShadowSentinel = ~(__sanitizer::u64)0;
|
||||
|
||||
// Reasonable values are 4 (for 1/16th shadow) and 6 (for 1/64th).
|
||||
constexpr __sanitizer::uptr kShadowScale = 4;
|
||||
constexpr __sanitizer::uptr kShadowAlignment = 1ULL << kShadowScale;
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
# define HWASAN_FIXED_MAPPING 0
|
||||
#else
|
||||
# define HWASAN_FIXED_MAPPING 1
|
||||
#endif
|
||||
|
||||
#if HWASAN_FIXED_MAPPING
|
||||
# define SHADOW_OFFSET (0)
|
||||
# define HWASAN_PREMAP_SHADOW 0
|
||||
#else
|
||||
# define SHADOW_OFFSET (__hwasan_shadow_memory_dynamic_address)
|
||||
# define HWASAN_PREMAP_SHADOW 1
|
||||
#endif
|
||||
|
||||
#define SHADOW_GRANULARITY (1ULL << kShadowScale)
|
||||
|
||||
#define MEM_TO_SHADOW(mem) (((uptr)(mem) >> kShadowScale) + SHADOW_OFFSET)
|
||||
#define SHADOW_TO_MEM(shadow) (((uptr)(shadow) - SHADOW_OFFSET) << kShadowScale)
|
||||
|
||||
#define MEM_TO_SHADOW_SIZE(size) ((uptr)(size) >> kShadowScale)
|
||||
|
||||
#define MEM_IS_APP(mem) MemIsApp((uptr)(mem))
|
||||
constexpr uptr kShadowScale = 4;
|
||||
constexpr uptr kShadowAlignment = 1ULL << kShadowScale;
|
||||
|
||||
namespace __hwasan {
|
||||
|
||||
inline uptr MemToShadow(uptr untagged_addr) {
|
||||
return (untagged_addr >> kShadowScale) +
|
||||
__hwasan_shadow_memory_dynamic_address;
|
||||
}
|
||||
inline uptr ShadowToMem(uptr shadow_addr) {
|
||||
return (shadow_addr - __hwasan_shadow_memory_dynamic_address) << kShadowScale;
|
||||
}
|
||||
inline uptr MemToShadowSize(uptr size) {
|
||||
return size >> kShadowScale;
|
||||
}
|
||||
|
||||
bool MemIsApp(uptr p);
|
||||
|
||||
} // namespace __hwasan
|
||||
|
|
|
|||
45
contrib/compiler-rt/lib/hwasan/hwasan_memintrinsics.cc
Normal file
45
contrib/compiler-rt/lib/hwasan/hwasan_memintrinsics.cc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
//===-- hwasan_memintrinsics.cc ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file is a part of HWAddressSanitizer and contains HWASAN versions of
|
||||
/// memset, memcpy and memmove
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <string.h>
|
||||
#include "hwasan.h"
|
||||
#include "hwasan_checks.h"
|
||||
#include "hwasan_flags.h"
|
||||
#include "hwasan_interface_internal.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
using namespace __hwasan;
|
||||
|
||||
void *__hwasan_memset(void *block, int c, uptr size) {
|
||||
CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
|
||||
reinterpret_cast<uptr>(block), size);
|
||||
return memset(UntagPtr(block), c, size);
|
||||
}
|
||||
|
||||
void *__hwasan_memcpy(void *to, const void *from, uptr size) {
|
||||
CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
|
||||
reinterpret_cast<uptr>(to), size);
|
||||
CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
|
||||
reinterpret_cast<uptr>(from), size);
|
||||
return memcpy(UntagPtr(to), UntagPtr(from), size);
|
||||
}
|
||||
|
||||
void *__hwasan_memmove(void *to, const void *from, uptr size) {
|
||||
CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
|
||||
reinterpret_cast<uptr>(to), size);
|
||||
CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
|
||||
reinterpret_cast<uptr>(from), size);
|
||||
return memmove(UntagPtr(to), UntagPtr(from), size);
|
||||
}
|
||||
|
|
@ -51,7 +51,7 @@ void *operator new[](size_t size, std::nothrow_t const&) {
|
|||
|
||||
#define OPERATOR_DELETE_BODY \
|
||||
GET_MALLOC_STACK_TRACE; \
|
||||
if (ptr) HwasanDeallocate(&stack, ptr)
|
||||
if (ptr) hwasan_free(ptr, &stack)
|
||||
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===-- hwasan_poisoning.cc ---------------------------------------*- C++ -*-===//
|
||||
//===-- hwasan_poisoning.cc -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -22,8 +22,8 @@ namespace __hwasan {
|
|||
uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) {
|
||||
CHECK(IsAligned(p, kShadowAlignment));
|
||||
CHECK(IsAligned(size, kShadowAlignment));
|
||||
uptr shadow_start = MEM_TO_SHADOW(p);
|
||||
uptr shadow_size = MEM_TO_SHADOW_SIZE(size);
|
||||
uptr shadow_start = MemToShadow(p);
|
||||
uptr shadow_size = MemToShadowSize(size);
|
||||
internal_memset((void *)shadow_start, tag, shadow_size);
|
||||
return AddTagToPointer(p, tag);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===-- hwasan_poisoning.h ----------------------------------------*- C++ -*-===//
|
||||
//===-- hwasan_poisoning.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
|
|||
|
|
@ -15,18 +15,64 @@
|
|||
#include "hwasan.h"
|
||||
#include "hwasan_allocator.h"
|
||||
#include "hwasan_mapping.h"
|
||||
#include "hwasan_thread.h"
|
||||
#include "hwasan_thread_list.h"
|
||||
#include "sanitizer_common/sanitizer_allocator_internal.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_mutex.h"
|
||||
#include "sanitizer_common/sanitizer_report_decorator.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
#include "sanitizer_common/sanitizer_stacktrace_printer.h"
|
||||
#include "sanitizer_common/sanitizer_symbolizer.h"
|
||||
|
||||
using namespace __sanitizer;
|
||||
|
||||
namespace __hwasan {
|
||||
|
||||
class ScopedReport {
|
||||
public:
|
||||
ScopedReport(bool fatal = false) : error_message_(1), fatal(fatal) {
|
||||
BlockingMutexLock lock(&error_message_lock_);
|
||||
error_message_ptr_ = fatal ? &error_message_ : nullptr;
|
||||
}
|
||||
|
||||
~ScopedReport() {
|
||||
BlockingMutexLock lock(&error_message_lock_);
|
||||
if (fatal) {
|
||||
SetAbortMessage(error_message_.data());
|
||||
Die();
|
||||
}
|
||||
error_message_ptr_ = nullptr;
|
||||
}
|
||||
|
||||
static void MaybeAppendToErrorMessage(const char *msg) {
|
||||
BlockingMutexLock lock(&error_message_lock_);
|
||||
if (!error_message_ptr_)
|
||||
return;
|
||||
uptr len = internal_strlen(msg);
|
||||
uptr old_size = error_message_ptr_->size();
|
||||
error_message_ptr_->resize(old_size + len);
|
||||
// overwrite old trailing '\0', keep new trailing '\0' untouched.
|
||||
internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len);
|
||||
}
|
||||
private:
|
||||
ScopedErrorReportLock error_report_lock_;
|
||||
InternalMmapVector<char> error_message_;
|
||||
bool fatal;
|
||||
|
||||
static InternalMmapVector<char> *error_message_ptr_;
|
||||
static BlockingMutex error_message_lock_;
|
||||
};
|
||||
|
||||
InternalMmapVector<char> *ScopedReport::error_message_ptr_;
|
||||
BlockingMutex ScopedReport::error_message_lock_;
|
||||
|
||||
// If there is an active ScopedReport, append to its error message.
|
||||
void AppendToErrorMessageBuffer(const char *buffer) {
|
||||
ScopedReport::MaybeAppendToErrorMessage(buffer);
|
||||
}
|
||||
|
||||
static StackTrace GetStackTraceFromId(u32 id) {
|
||||
CHECK(id);
|
||||
StackTrace res = StackDepotGet(id);
|
||||
|
|
@ -34,100 +80,344 @@ static StackTrace GetStackTraceFromId(u32 id) {
|
|||
return res;
|
||||
}
|
||||
|
||||
// A RAII object that holds a copy of the current thread stack ring buffer.
|
||||
// The actual stack buffer may change while we are iterating over it (for
|
||||
// example, Printf may call syslog() which can itself be built with hwasan).
|
||||
class SavedStackAllocations {
|
||||
public:
|
||||
SavedStackAllocations(StackAllocationsRingBuffer *rb) {
|
||||
uptr size = rb->size() * sizeof(uptr);
|
||||
void *storage =
|
||||
MmapAlignedOrDieOnFatalError(size, size * 2, "saved stack allocations");
|
||||
new (&rb_) StackAllocationsRingBuffer(*rb, storage);
|
||||
}
|
||||
|
||||
~SavedStackAllocations() {
|
||||
StackAllocationsRingBuffer *rb = get();
|
||||
UnmapOrDie(rb->StartOfStorage(), rb->size() * sizeof(uptr));
|
||||
}
|
||||
|
||||
StackAllocationsRingBuffer *get() {
|
||||
return (StackAllocationsRingBuffer *)&rb_;
|
||||
}
|
||||
|
||||
private:
|
||||
uptr rb_;
|
||||
};
|
||||
|
||||
class Decorator: public __sanitizer::SanitizerCommonDecorator {
|
||||
public:
|
||||
Decorator() : SanitizerCommonDecorator() { }
|
||||
const char *Access() { return Blue(); }
|
||||
const char *Allocation() const { return Magenta(); }
|
||||
const char *Origin() const { return Magenta(); }
|
||||
const char *Name() const { return Green(); }
|
||||
const char *Location() { return Green(); }
|
||||
const char *Thread() { return Green(); }
|
||||
};
|
||||
|
||||
struct HeapAddressDescription {
|
||||
uptr addr;
|
||||
u32 alloc_stack_id;
|
||||
u32 free_stack_id;
|
||||
|
||||
void Print() const {
|
||||
Decorator d;
|
||||
if (free_stack_id) {
|
||||
Printf("%sfreed here:%s\n", d.Allocation(), d.Default());
|
||||
GetStackTraceFromId(free_stack_id).Print();
|
||||
Printf("%spreviously allocated here:%s\n", d.Allocation(), d.Default());
|
||||
} else {
|
||||
Printf("%sallocated here:%s\n", d.Allocation(), d.Default());
|
||||
// Returns the index of the rb element that matches tagged_addr (plus one),
|
||||
// or zero if found nothing.
|
||||
uptr FindHeapAllocation(HeapAllocationsRingBuffer *rb,
|
||||
uptr tagged_addr,
|
||||
HeapAllocationRecord *har) {
|
||||
if (!rb) return 0;
|
||||
for (uptr i = 0, size = rb->size(); i < size; i++) {
|
||||
auto h = (*rb)[i];
|
||||
if (h.tagged_addr <= tagged_addr &&
|
||||
h.tagged_addr + h.requested_size > tagged_addr) {
|
||||
*har = h;
|
||||
return i + 1;
|
||||
}
|
||||
GetStackTraceFromId(alloc_stack_id).Print();
|
||||
}
|
||||
};
|
||||
|
||||
bool GetHeapAddressInformation(uptr addr, uptr access_size,
|
||||
HeapAddressDescription *description) {
|
||||
HwasanChunkView chunk = FindHeapChunkByAddress(addr);
|
||||
if (!chunk.IsValid())
|
||||
return false;
|
||||
description->addr = addr;
|
||||
description->alloc_stack_id = chunk.GetAllocStackId();
|
||||
description->free_stack_id = chunk.GetFreeStackId();
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PrintAddressDescription(uptr addr, uptr access_size) {
|
||||
HeapAddressDescription heap_description;
|
||||
if (GetHeapAddressInformation(addr, access_size, &heap_description)) {
|
||||
heap_description.Print();
|
||||
return;
|
||||
}
|
||||
// We exhausted our possibilities. Bail out.
|
||||
Printf("HWAddressSanitizer can not describe address in more detail.\n");
|
||||
}
|
||||
|
||||
void ReportInvalidAccess(StackTrace *stack, u32 origin) {
|
||||
ScopedErrorReportLock l;
|
||||
|
||||
void PrintAddressDescription(
|
||||
uptr tagged_addr, uptr access_size,
|
||||
StackAllocationsRingBuffer *current_stack_allocations) {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
Report("WARNING: HWAddressSanitizer: invalid access\n");
|
||||
Printf("%s", d.Default());
|
||||
stack->Print();
|
||||
ReportErrorSummary("invalid-access", stack);
|
||||
int num_descriptions_printed = 0;
|
||||
uptr untagged_addr = UntagAddr(tagged_addr);
|
||||
|
||||
// Print some very basic information about the address, if it's a heap.
|
||||
HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
|
||||
if (uptr beg = chunk.Beg()) {
|
||||
uptr size = chunk.ActualSize();
|
||||
Printf("%s[%p,%p) is a %s %s heap chunk; "
|
||||
"size: %zd offset: %zd\n%s",
|
||||
d.Location(),
|
||||
beg, beg + size,
|
||||
chunk.FromSmallHeap() ? "small" : "large",
|
||||
chunk.IsAllocated() ? "allocated" : "unallocated",
|
||||
size, untagged_addr - beg,
|
||||
d.Default());
|
||||
}
|
||||
|
||||
// Check if this looks like a heap buffer overflow by scanning
|
||||
// the shadow left and right and looking for the first adjacent
|
||||
// object with a different memory tag. If that tag matches addr_tag,
|
||||
// check the allocator if it has a live chunk there.
|
||||
tag_t addr_tag = GetTagFromPointer(tagged_addr);
|
||||
tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
|
||||
if (*tag_ptr != addr_tag) { // should be true usually.
|
||||
tag_t *left = tag_ptr, *right = tag_ptr;
|
||||
// scan left.
|
||||
for (int i = 0; i < 1000 && *left == *tag_ptr; i++, left--){}
|
||||
// scan right.
|
||||
for (int i = 0; i < 1000 && *right == *tag_ptr; i++, right++){}
|
||||
// Chose the object that has addr_tag and that is closer to addr.
|
||||
tag_t *candidate = nullptr;
|
||||
if (*right == addr_tag && *left == addr_tag)
|
||||
candidate = right - tag_ptr < tag_ptr - left ? right : left;
|
||||
else if (*right == addr_tag)
|
||||
candidate = right;
|
||||
else if (*left == addr_tag)
|
||||
candidate = left;
|
||||
|
||||
if (candidate) {
|
||||
uptr mem = ShadowToMem(reinterpret_cast<uptr>(candidate));
|
||||
HwasanChunkView chunk = FindHeapChunkByAddress(mem);
|
||||
if (chunk.IsAllocated()) {
|
||||
Printf("%s", d.Location());
|
||||
Printf(
|
||||
"%p is located %zd bytes to the %s of %zd-byte region [%p,%p)\n",
|
||||
untagged_addr,
|
||||
candidate == left ? untagged_addr - chunk.End()
|
||||
: chunk.Beg() - untagged_addr,
|
||||
candidate == right ? "left" : "right", chunk.UsedSize(),
|
||||
chunk.Beg(), chunk.End());
|
||||
Printf("%s", d.Allocation());
|
||||
Printf("allocated here:\n");
|
||||
Printf("%s", d.Default());
|
||||
GetStackTraceFromId(chunk.GetAllocStackId()).Print();
|
||||
num_descriptions_printed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
|
||||
// Scan all threads' ring buffers to find if it's a heap-use-after-free.
|
||||
HeapAllocationRecord har;
|
||||
if (uptr D = FindHeapAllocation(t->heap_allocations(), tagged_addr, &har)) {
|
||||
Printf("%s", d.Location());
|
||||
Printf("%p is located %zd bytes inside of %zd-byte region [%p,%p)\n",
|
||||
untagged_addr, untagged_addr - UntagAddr(har.tagged_addr),
|
||||
har.requested_size, UntagAddr(har.tagged_addr),
|
||||
UntagAddr(har.tagged_addr) + har.requested_size);
|
||||
Printf("%s", d.Allocation());
|
||||
Printf("freed by thread T%zd here:\n", t->unique_id());
|
||||
Printf("%s", d.Default());
|
||||
GetStackTraceFromId(har.free_context_id).Print();
|
||||
|
||||
Printf("%s", d.Allocation());
|
||||
Printf("previously allocated here:\n", t);
|
||||
Printf("%s", d.Default());
|
||||
GetStackTraceFromId(har.alloc_context_id).Print();
|
||||
|
||||
// Print a developer note: the index of this heap object
|
||||
// in the thread's deallocation ring buffer.
|
||||
Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", D,
|
||||
flags()->heap_history_size);
|
||||
|
||||
t->Announce();
|
||||
num_descriptions_printed++;
|
||||
}
|
||||
|
||||
// Very basic check for stack memory.
|
||||
if (t->AddrIsInStack(untagged_addr)) {
|
||||
Printf("%s", d.Location());
|
||||
Printf("Address %p is located in stack of thread T%zd\n", untagged_addr,
|
||||
t->unique_id());
|
||||
Printf("%s", d.Default());
|
||||
t->Announce();
|
||||
|
||||
// Temporary report section, needs to be improved.
|
||||
Printf("Previously allocated frames:\n");
|
||||
auto *sa = (t == GetCurrentThread() && current_stack_allocations)
|
||||
? current_stack_allocations
|
||||
: t->stack_allocations();
|
||||
uptr frames = Min((uptr)flags()->stack_history_size, sa->size());
|
||||
InternalScopedString frame_desc(GetPageSizeCached() * 2);
|
||||
for (uptr i = 0; i < frames; i++) {
|
||||
uptr record = (*sa)[i];
|
||||
if (!record)
|
||||
break;
|
||||
uptr sp = (record >> 48) << 4;
|
||||
uptr pc_mask = (1ULL << 48) - 1;
|
||||
uptr pc = record & pc_mask;
|
||||
if (SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc)) {
|
||||
frame_desc.append(" sp: 0x%zx pc: %p ", sp, pc);
|
||||
RenderFrame(&frame_desc, "in %f %s:%l\n", 0, frame->info,
|
||||
common_flags()->symbolize_vs_style,
|
||||
common_flags()->strip_path_prefix);
|
||||
frame->ClearAll();
|
||||
if (auto Descr = GetStackFrameDescr(pc))
|
||||
frame_desc.append(" %s\n", Descr);
|
||||
}
|
||||
Printf("%s", frame_desc.data());
|
||||
frame_desc.clear();
|
||||
}
|
||||
|
||||
num_descriptions_printed++;
|
||||
}
|
||||
});
|
||||
|
||||
// Print the remaining threads, as an extra information, 1 line per thread.
|
||||
hwasanThreadList().VisitAllLiveThreads([&](Thread *t) { t->Announce(); });
|
||||
|
||||
if (!num_descriptions_printed)
|
||||
// We exhausted our possibilities. Bail out.
|
||||
Printf("HWAddressSanitizer can not describe address in more detail.\n");
|
||||
}
|
||||
|
||||
void ReportStats() {}
|
||||
|
||||
void ReportInvalidAccessInsideAddressRange(const char *what, const void *start,
|
||||
uptr size, uptr offset) {
|
||||
ScopedErrorReportLock l;
|
||||
static void PrintTagsAroundAddr(tag_t *tag_ptr) {
|
||||
Printf(
|
||||
"Memory tags around the buggy address (one tag corresponds to %zd "
|
||||
"bytes):\n", kShadowAlignment);
|
||||
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
Printf("%sTag mismatch in %s%s%s at offset %zu inside [%p, %zu)%s\n",
|
||||
d.Warning(), d.Name(), what, d.Warning(), offset, start, size,
|
||||
d.Default());
|
||||
PrintAddressDescription((uptr)start + offset, 1);
|
||||
// if (__sanitizer::Verbosity())
|
||||
// DescribeMemoryRange(start, size);
|
||||
const uptr row_len = 16; // better be power of two.
|
||||
const uptr num_rows = 17;
|
||||
tag_t *center_row_beg = reinterpret_cast<tag_t *>(
|
||||
RoundDownTo(reinterpret_cast<uptr>(tag_ptr), row_len));
|
||||
tag_t *beg_row = center_row_beg - row_len * (num_rows / 2);
|
||||
tag_t *end_row = center_row_beg + row_len * (num_rows / 2);
|
||||
InternalScopedString s(GetPageSizeCached() * 8);
|
||||
for (tag_t *row = beg_row; row < end_row; row += row_len) {
|
||||
s.append("%s", row == center_row_beg ? "=>" : " ");
|
||||
for (uptr i = 0; i < row_len; i++) {
|
||||
s.append("%s", row + i == tag_ptr ? "[" : " ");
|
||||
s.append("%02x", row[i]);
|
||||
s.append("%s", row + i == tag_ptr ? "]" : " ");
|
||||
}
|
||||
s.append("%s\n", row == center_row_beg ? "<=" : " ");
|
||||
}
|
||||
Printf("%s", s.data());
|
||||
}
|
||||
|
||||
void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
|
||||
bool is_store) {
|
||||
ScopedErrorReportLock l;
|
||||
void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
|
||||
ScopedReport R(flags()->halt_on_error);
|
||||
|
||||
uptr untagged_addr = UntagAddr(tagged_addr);
|
||||
tag_t ptr_tag = GetTagFromPointer(tagged_addr);
|
||||
tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
|
||||
tag_t mem_tag = *tag_ptr;
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
uptr address = GetAddressFromPointer(addr);
|
||||
Printf("%s of size %zu at %p\n", is_store ? "WRITE" : "READ", access_size,
|
||||
address);
|
||||
|
||||
tag_t ptr_tag = GetTagFromPointer(addr);
|
||||
tag_t mem_tag = *(tag_t *)MEM_TO_SHADOW(address);
|
||||
Printf("pointer tag 0x%x\nmemory tag 0x%x\n", ptr_tag, mem_tag);
|
||||
Printf("%s", d.Error());
|
||||
uptr pc = stack->size ? stack->trace[0] : 0;
|
||||
const char *bug_type = "invalid-free";
|
||||
Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type,
|
||||
untagged_addr, pc);
|
||||
Printf("%s", d.Access());
|
||||
Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag);
|
||||
Printf("%s", d.Default());
|
||||
|
||||
stack->Print();
|
||||
|
||||
PrintAddressDescription(address, access_size);
|
||||
PrintAddressDescription(tagged_addr, 0, nullptr);
|
||||
|
||||
ReportErrorSummary("tag-mismatch", stack);
|
||||
PrintTagsAroundAddr(tag_ptr);
|
||||
|
||||
ReportErrorSummary(bug_type, stack);
|
||||
}
|
||||
|
||||
void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
|
||||
uptr tail_size, const u8 *expected) {
|
||||
ScopedReport R(flags()->halt_on_error);
|
||||
Decorator d;
|
||||
uptr untagged_addr = UntagAddr(tagged_addr);
|
||||
Printf("%s", d.Error());
|
||||
const char *bug_type = "alocation-tail-overwritten";
|
||||
Report("ERROR: %s: %s; heap object [%p,%p) of size %zd\n", SanitizerToolName,
|
||||
bug_type, untagged_addr, untagged_addr + orig_size, orig_size);
|
||||
Printf("\n%s", d.Default());
|
||||
stack->Print();
|
||||
HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
|
||||
if (chunk.Beg()) {
|
||||
Printf("%s", d.Allocation());
|
||||
Printf("allocated here:\n");
|
||||
Printf("%s", d.Default());
|
||||
GetStackTraceFromId(chunk.GetAllocStackId()).Print();
|
||||
}
|
||||
|
||||
InternalScopedString s(GetPageSizeCached() * 8);
|
||||
CHECK_GT(tail_size, 0U);
|
||||
CHECK_LT(tail_size, kShadowAlignment);
|
||||
u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size);
|
||||
s.append("Tail contains: ");
|
||||
for (uptr i = 0; i < kShadowAlignment - tail_size; i++)
|
||||
s.append(".. ");
|
||||
for (uptr i = 0; i < tail_size; i++)
|
||||
s.append("%02x ", tail[i]);
|
||||
s.append("\n");
|
||||
s.append("Expected: ");
|
||||
for (uptr i = 0; i < kShadowAlignment - tail_size; i++)
|
||||
s.append(".. ");
|
||||
for (uptr i = 0; i < tail_size; i++)
|
||||
s.append("%02x ", expected[i]);
|
||||
s.append("\n");
|
||||
s.append(" ");
|
||||
for (uptr i = 0; i < kShadowAlignment - tail_size; i++)
|
||||
s.append(" ");
|
||||
for (uptr i = 0; i < tail_size; i++)
|
||||
s.append("%s ", expected[i] != tail[i] ? "^^" : " ");
|
||||
|
||||
s.append("\nThis error occurs when a buffer overflow overwrites memory\n"
|
||||
"to the right of a heap object, but within the %zd-byte granule, e.g.\n"
|
||||
" char *x = new char[20];\n"
|
||||
" x[25] = 42;\n"
|
||||
"By default %s does not detect such bugs at the time of write,\n"
|
||||
"but can detect them at the time of free/delete.\n"
|
||||
"To disable this feature set HWASAN_OPTIONS=free_checks_tail_magic=0;\n"
|
||||
"To enable checking at the time of access, set "
|
||||
"HWASAN_OPTIONS=malloc_align_right to non-zero\n\n",
|
||||
kShadowAlignment, SanitizerToolName);
|
||||
Printf("%s", s.data());
|
||||
GetCurrentThread()->Announce();
|
||||
|
||||
tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
|
||||
PrintTagsAroundAddr(tag_ptr);
|
||||
|
||||
ReportErrorSummary(bug_type, stack);
|
||||
}
|
||||
|
||||
void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
|
||||
bool is_store, bool fatal) {
|
||||
ScopedReport R(fatal);
|
||||
SavedStackAllocations current_stack_allocations(
|
||||
GetCurrentThread()->stack_allocations());
|
||||
|
||||
Decorator d;
|
||||
Printf("%s", d.Error());
|
||||
uptr untagged_addr = UntagAddr(tagged_addr);
|
||||
// TODO: when possible, try to print heap-use-after-free, etc.
|
||||
const char *bug_type = "tag-mismatch";
|
||||
uptr pc = stack->size ? stack->trace[0] : 0;
|
||||
Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type,
|
||||
untagged_addr, pc);
|
||||
|
||||
Thread *t = GetCurrentThread();
|
||||
|
||||
tag_t ptr_tag = GetTagFromPointer(tagged_addr);
|
||||
tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
|
||||
tag_t mem_tag = *tag_ptr;
|
||||
Printf("%s", d.Access());
|
||||
Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread T%zd\n",
|
||||
is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag,
|
||||
mem_tag, t->unique_id());
|
||||
Printf("%s", d.Default());
|
||||
|
||||
stack->Print();
|
||||
|
||||
PrintAddressDescription(tagged_addr, access_size,
|
||||
current_stack_allocations.get());
|
||||
t->Announce();
|
||||
|
||||
PrintTagsAroundAddr(tag_ptr);
|
||||
|
||||
ReportErrorSummary(bug_type, stack);
|
||||
}
|
||||
|
||||
} // namespace __hwasan
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue