From fa321004f3f6288d3ee2eefa6b02177131882dca Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Fri, 1 Nov 2024 15:33:03 +0800 Subject: [PATCH] libsanitizer: merge from upstream (61a6439f35b6de28) --- libsanitizer/MERGE | 2 +- libsanitizer/asan/Makefile.am | 1 - libsanitizer/asan/Makefile.in | 5 +- libsanitizer/asan/asan_allocator.cpp | 10 +- libsanitizer/asan/asan_allocator.h | 36 +- libsanitizer/asan/asan_descriptions.cpp | 52 +- libsanitizer/asan/asan_descriptions.h | 2 - libsanitizer/asan/asan_errors.cpp | 20 +- libsanitizer/asan/asan_errors.h | 19 + libsanitizer/asan/asan_flags.cpp | 96 +- libsanitizer/asan/asan_fuchsia.cpp | 7 +- libsanitizer/asan/asan_globals.cpp | 278 ++- libsanitizer/asan/asan_globals_win.cpp | 12 +- libsanitizer/asan/asan_interceptors.cpp | 139 +- libsanitizer/asan/asan_interceptors.h | 15 +- libsanitizer/asan/asan_internal.h | 4 +- libsanitizer/asan/asan_linux.cpp | 29 +- libsanitizer/asan/asan_lock.h | 0 libsanitizer/asan/asan_mac.cpp | 12 +- libsanitizer/asan/asan_malloc_linux.cpp | 16 +- libsanitizer/asan/asan_malloc_mac.cpp | 5 +- libsanitizer/asan/asan_malloc_win.cpp | 97 +- libsanitizer/asan/asan_malloc_win_thunk.cpp | 229 ++ libsanitizer/asan/asan_mapping.h | 9 +- libsanitizer/asan/asan_new_delete.cpp | 9 - libsanitizer/asan/asan_poisoning.cpp | 184 +- libsanitizer/asan/asan_posix.cpp | 47 +- libsanitizer/asan/asan_preinit.cpp | 10 +- libsanitizer/asan/asan_premap_shadow.cpp | 3 +- libsanitizer/asan/asan_report.cpp | 43 +- libsanitizer/asan/asan_report.h | 3 + libsanitizer/asan/asan_rtl.cpp | 65 +- libsanitizer/asan/asan_rtl_x86_64.S | 10 + libsanitizer/asan/asan_suppressions.cpp | 12 +- libsanitizer/asan/asan_thread.cpp | 40 +- libsanitizer/asan/asan_thread.h | 11 +- libsanitizer/asan/asan_win.cpp | 12 +- .../asan/asan_win_common_runtime_thunk.cpp | 112 + .../asan/asan_win_common_runtime_thunk.h | 38 + libsanitizer/asan/asan_win_dll_thunk.cpp | 165 -- .../asan/asan_win_dynamic_runtime_thunk.cpp | 104 +- .../asan/asan_win_static_runtime_thunk.cpp | 113 + .../asan/asan_win_weak_interception.cpp | 22 - libsanitizer/builtins/assembly.h | 5 +- libsanitizer/hwasan/hwasan.cpp | 8 +- libsanitizer/hwasan/hwasan.h | 10 +- .../hwasan/hwasan_allocation_functions.cpp | 8 +- libsanitizer/hwasan/hwasan_allocator.cpp | 7 +- libsanitizer/hwasan/hwasan_checks.h | 1 - libsanitizer/hwasan/hwasan_dynamic_shadow.cpp | 17 +- libsanitizer/hwasan/hwasan_flags.inc | 7 + libsanitizer/hwasan/hwasan_interceptors.cpp | 7 +- .../hwasan/hwasan_interface_internal.h | 3 + libsanitizer/hwasan/hwasan_linux.cpp | 108 +- libsanitizer/hwasan/hwasan_preinit.cpp | 10 +- libsanitizer/hwasan/hwasan_report.cpp | 161 +- libsanitizer/hwasan/hwasan_thread.cpp | 8 +- libsanitizer/hwasan/hwasan_thread_list.cpp | 9 +- libsanitizer/hwasan/hwasan_thread_list.h | 8 +- .../include/sanitizer/allocator_interface.h | 15 +- .../include/sanitizer/common_interface_defs.h | 39 +- .../include/sanitizer/hwasan_interface.h | 4 + .../include/sanitizer/linux_syscall_hooks.h | 16 +- .../include/sanitizer/memprof_interface.h | 6 + .../include/sanitizer/nsan_interface.h | 75 + .../include/sanitizer/rtsan_interface.h | 75 + .../include/sanitizer/ubsan_interface.h | 2 + libsanitizer/interception/interception.h | 35 +- .../interception/interception_linux.h | 16 +- .../interception/interception_type_test.cpp | 31 +- .../interception/interception_win.cpp | 237 +- libsanitizer/lsan/lsan.cpp | 3 +- libsanitizer/lsan/lsan.h | 1 + libsanitizer/lsan/lsan_allocator.cpp | 2 +- libsanitizer/lsan/lsan_common.cpp | 355 ++- libsanitizer/lsan/lsan_common.h | 5 + libsanitizer/lsan/lsan_common_linux.cpp | 2 +- libsanitizer/lsan/lsan_flags.inc | 7 + libsanitizer/lsan/lsan_fuchsia.cpp | 1 + libsanitizer/lsan/lsan_interceptors.cpp | 12 +- libsanitizer/lsan/lsan_posix.cpp | 45 +- libsanitizer/lsan/lsan_preinit.cpp | 8 +- libsanitizer/lsan/lsan_thread.cpp | 13 +- libsanitizer/sanitizer_common/Makefile.am | 6 +- libsanitizer/sanitizer_common/Makefile.in | 20 +- .../sanitizer_common/sancov_flags.cpp | 6 +- .../sanitizer_common/sanitizer_allocator.cpp | 7 +- .../sanitizer_allocator_dlsym.h | 13 +- .../sanitizer_allocator_interface.h | 2 + .../sanitizer_allocator_primary32.h | 2 +- .../sanitizer_allocator_primary64.h | 13 +- .../sanitizer_common/sanitizer_atomic.h | 14 +- .../sanitizer_common/sanitizer_atomic_clang.h | 85 +- .../sanitizer_atomic_clang_mips.h | 117 - .../sanitizer_atomic_clang_other.h | 85 - .../sanitizer_atomic_clang_x86.h | 113 - .../sanitizer_common/sanitizer_atomic_msvc.h | 8 +- .../sanitizer_common/sanitizer_bitvector.h | 8 +- .../sanitizer_chained_origin_depot.cpp | 6 +- .../sanitizer_chained_origin_depot.h | 4 +- .../sanitizer_common/sanitizer_common.cpp | 15 +- .../sanitizer_common/sanitizer_common.h | 61 +- .../sanitizer_common_interceptors.inc | 457 ++-- .../sanitizer_common_interface.inc | 9 + .../sanitizer_common_libcdep.cpp | 34 +- .../sanitizer_common_nolibc.cpp | 7 +- .../sanitizer_common_syscalls.inc | 68 +- .../sanitizer_coverage_fuchsia.cpp | 2 +- .../sanitizer_coverage_libcdep_new.cpp | 3 +- .../sanitizer_coverage_win_dll_thunk.cpp | 20 - ... sanitizer_coverage_win_runtime_thunk.cpp} | 21 +- ...nitizer_coverage_win_weak_interception.cpp | 23 - .../sanitizer_common/sanitizer_dense_map.h | 70 +- .../sanitizer_common/sanitizer_errno.cpp | 1 + .../sanitizer_common/sanitizer_errno_codes.h | 1 + .../sanitizer_common/sanitizer_file.cpp | 4 +- .../sanitizer_common/sanitizer_flags.inc | 7 + .../sanitizer_common/sanitizer_flat_map.h | 4 + .../sanitizer_common/sanitizer_freebsd.h | 137 -- .../sanitizer_common/sanitizer_fuchsia.cpp | 107 +- .../sanitizer_common/sanitizer_hash.h | 2 +- .../sanitizer_interface_internal.h | 10 + .../sanitizer_internal_defs.h | 45 +- .../sanitizer_common/sanitizer_libignore.cpp | 32 +- .../sanitizer_common/sanitizer_libignore.h | 35 +- .../sanitizer_common/sanitizer_linux.cpp | 2137 ++++++++++------- .../sanitizer_common/sanitizer_linux.h | 122 +- .../sanitizer_linux_libcdep.cpp | 728 +++--- .../sanitizer_common/sanitizer_linux_s390.cpp | 164 +- .../sanitizer_common/sanitizer_mac.cpp | 58 +- libsanitizer/sanitizer_common/sanitizer_mac.h | 20 - .../sanitizer_common/sanitizer_mallinfo.h | 4 + .../sanitizer_common/sanitizer_mutex.cpp | 6 +- .../sanitizer_placement_new.h | 4 +- .../sanitizer_common/sanitizer_platform.h | 17 +- .../sanitizer_platform_interceptors.h | 54 +- .../sanitizer_platform_limits_freebsd.cpp | 2 + .../sanitizer_platform_limits_freebsd.h | 24 +- .../sanitizer_platform_limits_linux.cpp | 5 +- .../sanitizer_platform_limits_openbsd.cpp | 0 .../sanitizer_platform_limits_openbsd.h | 0 .../sanitizer_platform_limits_posix.cpp | 57 +- .../sanitizer_platform_limits_posix.h | 32 +- .../sanitizer_common/sanitizer_posix.cpp | 22 +- .../sanitizer_common/sanitizer_posix.h | 32 +- .../sanitizer_posix_libcdep.cpp | 133 +- .../sanitizer_common/sanitizer_printf.cpp | 2 +- .../sanitizer_procmaps_bsd.cpp | 47 +- .../sanitizer_procmaps_common.cpp | 2 +- .../sanitizer_procmaps_mac.cpp | 66 +- .../sanitizer_procmaps_solaris.cpp | 4 + .../sanitizer_common/sanitizer_ptrauth.h | 46 +- .../sanitizer_redefine_builtins.h | 12 +- .../sanitizer_stack_store.cpp | 9 +- .../sanitizer_common/sanitizer_stackdepot.cpp | 8 +- .../sanitizer_common/sanitizer_stackdepot.h | 4 +- .../sanitizer_stackdepotbase.h | 31 +- .../sanitizer_common/sanitizer_stacktrace.cpp | 17 +- .../sanitizer_stacktrace_libcdep.cpp | 20 +- .../sanitizer_stacktrace_printer.cpp | 45 +- .../sanitizer_stacktrace_printer.h | 48 +- .../sanitizer_stacktrace_sparc.cpp | 11 +- .../sanitizer_stoptheworld_linux_libcdep.cpp | 19 +- .../sanitizer_stoptheworld_netbsd_libcdep.cpp | 4 +- .../sanitizer_suppressions.cpp | 7 +- .../sanitizer_common/sanitizer_symbolizer.h | 30 +- .../sanitizer_symbolizer_libcdep.cpp | 7 + .../sanitizer_symbolizer_mac.cpp | 4 +- .../sanitizer_symbolizer_markup.cpp | 234 +- .../sanitizer_symbolizer_markup.h | 79 + ...> sanitizer_symbolizer_markup_constants.h} | 19 +- .../sanitizer_symbolizer_markup_fuchsia.cpp | 85 + .../sanitizer_symbolizer_posix_libcdep.cpp | 34 +- .../sanitizer_symbolizer_report.cpp | 77 +- .../sanitizer_symbolizer_report_fuchsia.cpp | 33 + .../sanitizer_symbolizer_win.cpp | 13 +- .../sanitizer_thread_arg_retval.cpp | 23 +- .../sanitizer_thread_arg_retval.h | 1 + .../sanitizer_thread_history.cpp | 72 + .../sanitizer_thread_history.h | 24 + .../sanitizer_thread_registry.cpp | 51 +- .../sanitizer_thread_registry.h | 11 +- .../sanitizer_tls_get_addr.cpp | 81 +- .../sanitizer_common/sanitizer_tls_get_addr.h | 4 - .../sanitizer_unwind_fuchsia.cpp | 66 + .../sanitizer_common/sanitizer_unwind_win.cpp | 7 + .../sanitizer_common/sanitizer_win.cpp | 107 +- .../sanitizer_win_dll_thunk.cpp | 101 - .../sanitizer_win_dll_thunk.h | 181 -- .../sanitizer_win_dynamic_runtime_thunk.cpp | 26 - .../sanitizer_win_immortalize.h | 71 + .../sanitizer_win_interception.cpp | 156 ++ .../sanitizer_win_interception.h | 32 + .../sanitizer_win_thunk_interception.cpp | 110 + .../sanitizer_win_thunk_interception.h | 88 + .../sanitizer_win_weak_interception.cpp | 94 - .../sanitizer_win_weak_interception.h | 32 - libsanitizer/tsan/tsan_defs.h | 2 +- libsanitizer/tsan/tsan_dispatch_defs.h | 7 - libsanitizer/tsan/tsan_interceptors_mac.cpp | 8 + libsanitizer/tsan/tsan_interceptors_posix.cpp | 187 +- libsanitizer/tsan/tsan_interface_ann.cpp | 2 +- libsanitizer/tsan/tsan_mman.cpp | 31 +- libsanitizer/tsan/tsan_mman.h | 4 +- libsanitizer/tsan/tsan_platform.h | 42 +- libsanitizer/tsan/tsan_platform_linux.cpp | 171 +- libsanitizer/tsan/tsan_platform_mac.cpp | 9 +- libsanitizer/tsan/tsan_platform_posix.cpp | 43 +- libsanitizer/tsan/tsan_preinit.cpp | 10 +- libsanitizer/tsan/tsan_report.cpp | 26 +- libsanitizer/tsan/tsan_rtl.cpp | 24 +- libsanitizer/tsan/tsan_rtl.h | 8 +- libsanitizer/tsan/tsan_rtl_aarch64.S | 7 + libsanitizer/tsan/tsan_rtl_access.cpp | 22 +- libsanitizer/tsan/tsan_rtl_mutex.cpp | 2 +- libsanitizer/tsan/tsan_rtl_ppc64.S | 1 - libsanitizer/tsan/tsan_rtl_thread.cpp | 20 +- libsanitizer/tsan/tsan_suppressions.cpp | 2 +- libsanitizer/tsan/tsan_vector_clock.h | 2 +- libsanitizer/ubsan/ubsan_diag.cpp | 6 +- libsanitizer/ubsan/ubsan_diag.h | 20 - libsanitizer/ubsan/ubsan_diag_standalone.cpp | 2 +- libsanitizer/ubsan/ubsan_flags.cpp | 1 - libsanitizer/ubsan/ubsan_handlers.cpp | 53 +- libsanitizer/ubsan/ubsan_handlers.h | 10 +- libsanitizer/ubsan/ubsan_handlers_cxx.cpp | 44 - libsanitizer/ubsan/ubsan_handlers_cxx.h | 13 - libsanitizer/ubsan/ubsan_init.cpp | 2 +- .../ubsan/ubsan_init_standalone_preinit.cpp | 4 +- libsanitizer/ubsan/ubsan_interface.inc | 2 - libsanitizer/ubsan/ubsan_platform.h | 2 - .../ubsan/ubsan_signals_standalone.cpp | 5 + .../ubsan/ubsan_type_hash_itanium.cpp | 2 +- libsanitizer/ubsan/ubsan_value.cpp | 17 +- libsanitizer/ubsan/ubsan_value.h | 33 +- libsanitizer/ubsan/ubsan_win_dll_thunk.cpp | 20 - ..._thunk.cpp => ubsan_win_runtime_thunk.cpp} | 11 +- .../ubsan/ubsan_win_weak_interception.cpp | 23 - 238 files changed, 7276 insertions(+), 4764 deletions(-) delete mode 100644 libsanitizer/asan/asan_lock.h create mode 100644 libsanitizer/asan/asan_malloc_win_thunk.cpp create mode 100644 libsanitizer/asan/asan_win_common_runtime_thunk.cpp create mode 100644 libsanitizer/asan/asan_win_common_runtime_thunk.h delete mode 100644 libsanitizer/asan/asan_win_dll_thunk.cpp create mode 100644 libsanitizer/asan/asan_win_static_runtime_thunk.cpp delete mode 100644 libsanitizer/asan/asan_win_weak_interception.cpp create mode 100644 libsanitizer/include/sanitizer/nsan_interface.h create mode 100644 libsanitizer/include/sanitizer/rtsan_interface.h delete mode 100644 libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h delete mode 100644 libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h delete mode 100644 libsanitizer/sanitizer_common/sanitizer_atomic_clang_x86.h delete mode 100644 libsanitizer/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp rename libsanitizer/sanitizer_common/{sanitizer_coverage_win_dynamic_runtime_thunk.cpp => sanitizer_coverage_win_runtime_thunk.cpp} (59%) delete mode 100644 libsanitizer/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp delete mode 100644 libsanitizer/sanitizer_common/sanitizer_freebsd.h delete mode 100644 libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp delete mode 100644 libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h create mode 100644 libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.h rename libsanitizer/sanitizer_common/{sanitizer_symbolizer_fuchsia.h => sanitizer_symbolizer_markup_constants.h} (69%) create mode 100644 libsanitizer/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp create mode 100644 libsanitizer/sanitizer_common/sanitizer_symbolizer_report_fuchsia.cpp create mode 100644 libsanitizer/sanitizer_common/sanitizer_thread_history.cpp create mode 100644 libsanitizer/sanitizer_common/sanitizer_thread_history.h create mode 100644 libsanitizer/sanitizer_common/sanitizer_unwind_fuchsia.cpp delete mode 100644 libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cpp delete mode 100644 libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.h delete mode 100644 libsanitizer/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp create mode 100644 libsanitizer/sanitizer_common/sanitizer_win_immortalize.h create mode 100644 libsanitizer/sanitizer_common/sanitizer_win_interception.cpp create mode 100644 libsanitizer/sanitizer_common/sanitizer_win_interception.h create mode 100644 libsanitizer/sanitizer_common/sanitizer_win_thunk_interception.cpp create mode 100644 libsanitizer/sanitizer_common/sanitizer_win_thunk_interception.h delete mode 100644 libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cpp delete mode 100644 libsanitizer/sanitizer_common/sanitizer_win_weak_interception.h delete mode 100644 libsanitizer/ubsan/ubsan_win_dll_thunk.cpp rename libsanitizer/ubsan/{ubsan_win_dynamic_runtime_thunk.cpp => ubsan_win_runtime_thunk.cpp} (62%) delete mode 100644 libsanitizer/ubsan/ubsan_win_weak_interception.cpp diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE index 2ee0843e704e..a223feef2f54 100644 --- a/libsanitizer/MERGE +++ b/libsanitizer/MERGE @@ -1,4 +1,4 @@ -c425db2eb558c26377edc04e062c0c1f999b2770 +61a6439f35b6de28ff4aff4450d6fca970292fd5 The first line of this file holds the git revision number of the last merge done from the master library sources. diff --git a/libsanitizer/asan/Makefile.am b/libsanitizer/asan/Makefile.am index 6af250e99d9e..5c77b3b2c672 100644 --- a/libsanitizer/asan/Makefile.am +++ b/libsanitizer/asan/Makefile.am @@ -46,7 +46,6 @@ asan_files = \ asan_suppressions.cpp \ asan_thread.cpp \ asan_win.cpp \ - asan_win_dll_thunk.cpp \ asan_win_dynamic_runtime_thunk.cpp \ asan_interceptors_vfork.S diff --git a/libsanitizer/asan/Makefile.in b/libsanitizer/asan/Makefile.in index ac72e13830fe..ef4b65dda975 100644 --- a/libsanitizer/asan/Makefile.in +++ b/libsanitizer/asan/Makefile.in @@ -160,8 +160,7 @@ am__objects_1 = asan_activation.lo asan_allocator.lo asan_debugging.lo \ asan_posix.lo asan_premap_shadow.lo asan_report.lo asan_rtl.lo \ asan_shadow_setup.lo asan_stack.lo asan_stats.lo \ asan_suppressions.lo asan_thread.lo asan_win.lo \ - asan_win_dll_thunk.lo asan_win_dynamic_runtime_thunk.lo \ - asan_interceptors_vfork.lo + asan_win_dynamic_runtime_thunk.lo asan_interceptors_vfork.lo am_libasan_la_OBJECTS = $(am__objects_1) libasan_la_OBJECTS = $(am_libasan_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) @@ -457,7 +456,6 @@ asan_files = \ asan_suppressions.cpp \ asan_thread.cpp \ asan_win.cpp \ - asan_win_dll_thunk.cpp \ asan_win_dynamic_runtime_thunk.cpp \ asan_interceptors_vfork.S @@ -619,7 +617,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_suppressions.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_thread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win_dll_thunk.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win_dynamic_runtime_thunk.Plo@am__quote@ .S.o: diff --git a/libsanitizer/asan/asan_allocator.cpp b/libsanitizer/asan/asan_allocator.cpp index 22dcf6132707..9e66f77217ec 100644 --- a/libsanitizer/asan/asan_allocator.cpp +++ b/libsanitizer/asan/asan_allocator.cpp @@ -717,7 +717,15 @@ struct Allocator { return; } - RunFreeHooks(ptr); + if (RunFreeHooks(ptr)) { + // Someone used __sanitizer_ignore_free_hook() and decided that they + // didn't want the memory to __sanitizer_ignore_free_hook freed right now. + // When they call free() on this pointer again at a later time, we should + // ignore the alloc-type mismatch and allow them to deallocate the pointer + // through free(), rather than the initial alloc type. + m->alloc_type = FROM_MALLOC; + return; + } // Must mark the chunk as quarantined before any changes to its metadata. // Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag. diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h index c3c4fae85b12..db8dc3bebfc6 100644 --- a/libsanitizer/asan/asan_allocator.h +++ b/libsanitizer/asan/asan_allocator.h @@ -182,42 +182,44 @@ static_assert(SizeClassMap::kNumClassesRounded <= 32, "allocator size and SizeClassMap tunings that allows us to " "reliably run all bringup tests in a sanitized environment."); -# else +# else // SANITIZER_RISCV64 // These are the default allocator tunings for non-RISCV environments where the // VMA is usually 48 bits and we have lots of space. const uptr kAllocatorSize = 0x40000000000ULL; // 4T. typedef DefaultSizeClassMap SizeClassMap; -# endif -# elif defined(__powerpc64__) +# endif // SANITIZER_RISCV64 +# else // SANITIZER_FUCHSIA + +# if SANITIZER_APPLE +const uptr kAllocatorSpace = 0x600000000000ULL; +# else // SANITIZER_APPLE const uptr kAllocatorSpace = ~(uptr)0; +# endif // SANITIZER_APPLE + +# if defined(__powerpc64__) const uptr kAllocatorSize = 0x20000000000ULL; // 2T. typedef DefaultSizeClassMap SizeClassMap; -# elif defined(__aarch64__) && SANITIZER_ANDROID +# elif defined(__aarch64__) && SANITIZER_ANDROID // Android needs to support 39, 42 and 48 bit VMA. -const uptr kAllocatorSpace = ~(uptr)0; const uptr kAllocatorSize = 0x2000000000ULL; // 128G. typedef VeryCompactSizeClassMap SizeClassMap; -# elif SANITIZER_RISCV64 -const uptr kAllocatorSpace = ~(uptr)0; +# elif SANITIZER_RISCV64 const uptr kAllocatorSize = 0x2000000000ULL; // 128G. typedef VeryDenseSizeClassMap SizeClassMap; -# elif defined(__sparc__) -const uptr kAllocatorSpace = ~(uptr)0; +# elif defined(__sparc__) const uptr kAllocatorSize = 0x20000000000ULL; // 2T. typedef DefaultSizeClassMap SizeClassMap; -# elif SANITIZER_WINDOWS -const uptr kAllocatorSpace = ~(uptr)0; +# elif SANITIZER_WINDOWS const uptr kAllocatorSize = 0x8000000000ULL; // 500G typedef DefaultSizeClassMap SizeClassMap; -# elif SANITIZER_APPLE -const uptr kAllocatorSpace = 0x600000000000ULL; +# elif SANITIZER_APPLE const uptr kAllocatorSize = 0x40000000000ULL; // 4T. typedef DefaultSizeClassMap SizeClassMap; -# else -const uptr kAllocatorSpace = 0x500000000000ULL; +# else const uptr kAllocatorSize = 0x40000000000ULL; // 4T. typedef DefaultSizeClassMap SizeClassMap; -# endif +# endif // defined(__powerpc64__) etc. +# endif // SANITIZER_FUCHSIA template struct AP64 { // Allocator64 parameters. Deliberately using a short name. static const uptr kSpaceBeg = kAllocatorSpace; @@ -232,7 +234,7 @@ struct AP64 { // Allocator64 parameters. Deliberately using a short name. template using PrimaryAllocatorASVT = SizeClassAllocator64>; using PrimaryAllocator = PrimaryAllocatorASVT; -#else // Fallback to SizeClassAllocator32. +#else // SANITIZER_CAN_USE_ALLOCATOR64. Fallback to SizeClassAllocator32. typedef CompactSizeClassMap SizeClassMap; template struct AP32 { diff --git a/libsanitizer/asan/asan_descriptions.cpp b/libsanitizer/asan/asan_descriptions.cpp index ef6f3e0a096f..caec79313e22 100644 --- a/libsanitizer/asan/asan_descriptions.cpp +++ b/libsanitizer/asan/asan_descriptions.cpp @@ -20,24 +20,20 @@ namespace __asan { AsanThreadIdAndName::AsanThreadIdAndName(AsanThreadContext *t) { - Init(t->tid, t->name); -} - -AsanThreadIdAndName::AsanThreadIdAndName(u32 tid) { - if (tid == kInvalidTid) { - Init(tid, ""); - } else { - asanThreadRegistry().CheckLocked(); - AsanThreadContext *t = GetThreadContextByTidLocked(tid); - Init(tid, t->name); + if (!t) { + internal_snprintf(name, sizeof(name), "T-1"); + return; } + int len = internal_snprintf(name, sizeof(name), "T%llu", t->unique_id); + CHECK(((unsigned int)len) < sizeof(name)); + if (internal_strlen(t->name)) + internal_snprintf(&name[len], sizeof(name) - len, " (%s)", t->name); } -void AsanThreadIdAndName::Init(u32 tid, const char *tname) { - int len = internal_snprintf(name, sizeof(name), "T%d", tid); - CHECK(((unsigned int)len) < sizeof(name)); - if (tname[0] != '\0') - internal_snprintf(&name[len], sizeof(name) - len, " (%s)", tname); +AsanThreadIdAndName::AsanThreadIdAndName(u32 tid) + : AsanThreadIdAndName( + tid == kInvalidTid ? nullptr : GetThreadContextByTidLocked(tid)) { + asanThreadRegistry().CheckLocked(); } void DescribeThread(AsanThreadContext *context) { @@ -48,9 +44,20 @@ void DescribeThread(AsanThreadContext *context) { return; } context->announced = true; + + AsanThreadContext *parent_context = + context->parent_tid == kInvalidTid + ? nullptr + : GetThreadContextByTidLocked(context->parent_tid); + + // `context->parent_tid` may point to reused slot. Check `unique_id` which + // is always smaller for the parent, always greater for a new user. + if (context->unique_id <= parent_context->unique_id) + parent_context = nullptr; + InternalScopedString str; str.AppendF("Thread %s", AsanThreadIdAndName(context).c_str()); - if (context->parent_tid == kInvalidTid) { + if (!parent_context) { str.Append(" created by unknown thread\n"); Printf("%s", str.data()); return; @@ -60,11 +67,8 @@ void DescribeThread(AsanThreadContext *context) { Printf("%s", str.data()); StackDepotGet(context->stack_id).Print(); // Recursively described parent thread if needed. - if (flags()->print_full_thread_history) { - AsanThreadContext *parent_context = - GetThreadContextByTidLocked(context->parent_tid); + if (flags()->print_full_thread_history) DescribeThread(parent_context); - } } // Shadow descriptions @@ -245,11 +249,11 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, InternalScopedString str; str.AppendF(" [%zd, %zd)", var.beg, var_end); // Render variable name. - str.AppendF(" '"); + str.Append(" '"); for (uptr i = 0; i < var.name_len; ++i) { str.AppendF("%c", var.name_pos[i]); } - str.AppendF("'"); + str.Append("'"); if (var.line > 0) { str.AppendF(" (line %zd)", var.line); } @@ -260,7 +264,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, str.AppendF("%s <== Memory access at offset %zd %s this variable%s\n", d.Location(), addr, pos_descr, d.Default()); } else { - str.AppendF("\n"); + str.Append("\n"); } Printf("%s", str.data()); } @@ -292,7 +296,7 @@ static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size, str.AppendF(" global variable '%s' defined in '", MaybeDemangleGlobalName(g.name)); PrintGlobalLocation(&str, g, /*print_module_name=*/false); - str.AppendF("' (0x%zx) of size %zu\n", g.beg, g.size); + str.AppendF("' (%p) of size %zu\n", (void *)g.beg, g.size); str.Append(d.Default()); PrintGlobalNameIfASCII(&str, g); Printf("%s", str.data()); diff --git a/libsanitizer/asan/asan_descriptions.h b/libsanitizer/asan/asan_descriptions.h index 650e2eb9173a..a614f47d461b 100644 --- a/libsanitizer/asan/asan_descriptions.h +++ b/libsanitizer/asan/asan_descriptions.h @@ -35,8 +35,6 @@ class AsanThreadIdAndName { const char *c_str() const { return &name[0]; } private: - void Init(u32 tid, const char *tname); - char name[128]; }; diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp index 3f2d13e31464..4f112cc5d1bc 100644 --- a/libsanitizer/asan/asan_errors.cpp +++ b/libsanitizer/asan/asan_errors.cpp @@ -327,9 +327,6 @@ void ErrorBadParamsToAnnotateContiguousContainer::Print() { " old_mid : %p\n" " new_mid : %p\n", (void *)beg, (void *)end, (void *)old_mid, (void *)new_mid); - uptr granularity = ASAN_SHADOW_GRANULARITY; - if (!IsAligned(beg, granularity)) - Report("ERROR: beg is not aligned by %zu\n", granularity); stack->Print(); ReportErrorSummary(scariness.GetDescription(), stack); } @@ -347,9 +344,20 @@ void ErrorBadParamsToAnnotateDoubleEndedContiguousContainer::Print() { (void *)storage_beg, (void *)storage_end, (void *)old_container_beg, (void *)old_container_end, (void *)new_container_beg, (void *)new_container_end); - uptr granularity = ASAN_SHADOW_GRANULARITY; - if (!IsAligned(storage_beg, granularity)) - Report("ERROR: storage_beg is not aligned by %zu\n", granularity); + stack->Print(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorBadParamsToCopyContiguousContainerAnnotations::Print() { + Report( + "ERROR: AddressSanitizer: bad parameters to " + "__sanitizer_copy_contiguous_container_annotations:\n" + " src_storage_beg : %p\n" + " src_storage_end : %p\n" + " dst_storage_beg : %p\n" + " new_storage_end : %p\n", + (void *)old_storage_beg, (void *)old_storage_end, (void *)new_storage_beg, + (void *)new_storage_end); stack->Print(); ReportErrorSummary(scariness.GetDescription(), stack); } diff --git a/libsanitizer/asan/asan_errors.h b/libsanitizer/asan/asan_errors.h index 634f6da54435..b3af655e6663 100644 --- a/libsanitizer/asan/asan_errors.h +++ b/libsanitizer/asan/asan_errors.h @@ -353,6 +353,24 @@ struct ErrorBadParamsToAnnotateDoubleEndedContiguousContainer : ErrorBase { void Print(); }; +struct ErrorBadParamsToCopyContiguousContainerAnnotations : ErrorBase { + const BufferedStackTrace *stack; + uptr old_storage_beg, old_storage_end, new_storage_beg, new_storage_end; + + ErrorBadParamsToCopyContiguousContainerAnnotations() = default; // (*) + ErrorBadParamsToCopyContiguousContainerAnnotations( + u32 tid, BufferedStackTrace *stack_, uptr old_storage_beg_, + uptr old_storage_end_, uptr new_storage_beg_, uptr new_storage_end_) + : ErrorBase(tid, 10, + "bad-__sanitizer_annotate_double_ended_contiguous_container"), + stack(stack_), + old_storage_beg(old_storage_beg_), + old_storage_end(old_storage_end_), + new_storage_beg(new_storage_beg_), + new_storage_end(new_storage_end_) {} + void Print(); +}; + struct ErrorODRViolation : ErrorBase { __asan_global global1, global2; u32 stack_id1, stack_id2; @@ -421,6 +439,7 @@ struct ErrorGeneric : ErrorBase { macro(StringFunctionSizeOverflow) \ macro(BadParamsToAnnotateContiguousContainer) \ macro(BadParamsToAnnotateDoubleEndedContiguousContainer) \ + macro(BadParamsToCopyContiguousContainerAnnotations) \ macro(ODRViolation) \ macro(InvalidPointerPair) \ macro(Generic) diff --git a/libsanitizer/asan/asan_flags.cpp b/libsanitizer/asan/asan_flags.cpp index 239898433232..56deb1b0d082 100644 --- a/libsanitizer/asan/asan_flags.cpp +++ b/libsanitizer/asan/asan_flags.cpp @@ -11,14 +11,16 @@ // ASan flag parsing logic. //===----------------------------------------------------------------------===// -#include "asan_activation.h" #include "asan_flags.h" + +#include "asan_activation.h" #include "asan_interface_internal.h" #include "asan_stack.h" #include "lsan/lsan_common.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_win_interception.h" #include "ubsan/ubsan_flags.h" #include "ubsan/ubsan_platform.h" @@ -47,7 +49,21 @@ static void RegisterAsanFlags(FlagParser *parser, Flags *f) { #undef ASAN_FLAG } -void InitializeFlags() { +static void DisplayHelpMessages(FlagParser *parser) { + // TODO(eugenis): dump all flags at verbosity>=2? + if (Verbosity()) { + ReportUnrecognizedFlags(); + } + + if (common_flags()->help) { + parser->PrintFlagDescriptions(); + } +} + +static void InitializeDefaultFlags() { + Flags *f = flags(); + FlagParser asan_parser; + // Set the default values and prepare for parsing ASan and common flags. SetCommonFlagsDefaults(); { @@ -60,10 +76,8 @@ void InitializeFlags() { cf.exitcode = 1; OverrideCommonFlags(cf); } - Flags *f = flags(); f->SetDefaults(); - FlagParser asan_parser; RegisterAsanFlags(&asan_parser, f); RegisterCommonFlags(&asan_parser); @@ -126,13 +140,12 @@ void InitializeFlags() { InitializeCommonFlags(); - // TODO(eugenis): dump all flags at verbosity>=2? - if (Verbosity()) ReportUnrecognizedFlags(); + // TODO(samsonov): print all of the flags (ASan, LSan, common). + DisplayHelpMessages(&asan_parser); +} - if (common_flags()->help) { - // TODO(samsonov): print all of the flags (ASan, LSan, common). - asan_parser.PrintFlagDescriptions(); - } +static void ProcessFlags() { + Flags *f = flags(); // Flag validation: if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) { @@ -199,6 +212,67 @@ void InitializeFlags() { } } +void InitializeFlags() { + InitializeDefaultFlags(); + ProcessFlags(); + +#if SANITIZER_WINDOWS + // On Windows, weak symbols are emulated by having the user program + // register which weak functions are defined. + // The ASAN DLL will initialize flags prior to user module initialization, + // so __asan_default_options will not point to the user definition yet. + // We still want to ensure we capture when options are passed via + // __asan_default_options, so we add a callback to be run + // when it is registered with the runtime. + + // There is theoretically time between the initial ProcessFlags and + // registering the weak callback where a weak function could be added and we + // would miss it, but in practice, InitializeFlags will always happen under + // the loader lock (if built as a DLL) and so will any calls to + // __sanitizer_register_weak_function. + AddRegisterWeakFunctionCallback( + reinterpret_cast(__asan_default_options), []() { + FlagParser asan_parser; + + RegisterAsanFlags(&asan_parser, flags()); + RegisterCommonFlags(&asan_parser); + asan_parser.ParseString(__asan_default_options()); + + DisplayHelpMessages(&asan_parser); + ProcessFlags(); + }); + +# if CAN_SANITIZE_UB + AddRegisterWeakFunctionCallback( + reinterpret_cast(__ubsan_default_options), []() { + FlagParser ubsan_parser; + + __ubsan::RegisterUbsanFlags(&ubsan_parser, __ubsan::flags()); + RegisterCommonFlags(&ubsan_parser); + ubsan_parser.ParseString(__ubsan_default_options()); + + // To match normal behavior, do not print UBSan help. + ProcessFlags(); + }); +# endif + +# if CAN_SANITIZE_LEAKS + AddRegisterWeakFunctionCallback( + reinterpret_cast(__lsan_default_options), []() { + FlagParser lsan_parser; + + __lsan::RegisterLsanFlags(&lsan_parser, __lsan::flags()); + RegisterCommonFlags(&lsan_parser); + lsan_parser.ParseString(__lsan_default_options()); + + // To match normal behavior, do not print LSan help. + ProcessFlags(); + }); +# endif + +#endif +} + } // namespace __asan SANITIZER_INTERFACE_WEAK_DEF(const char*, __asan_default_options, void) { diff --git a/libsanitizer/asan/asan_fuchsia.cpp b/libsanitizer/asan/asan_fuchsia.cpp index 2b15504123be..96c41e9d42ba 100644 --- a/libsanitizer/asan/asan_fuchsia.cpp +++ b/libsanitizer/asan/asan_fuchsia.cpp @@ -57,8 +57,6 @@ void AsanCheckDynamicRTPrereqs() {} void AsanCheckIncompatibleRT() {} void InitializeAsanInterceptors() {} -void *AsanDoesNotSupportStaticLinkage() { return nullptr; } - void InitializePlatformExceptionHandlers() {} void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { UNIMPLEMENTED(); @@ -123,8 +121,7 @@ static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, // In lieu of AsanThread::Create. AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__); - AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; - u32 tid = asanThreadRegistry().CreateThread(0, detached, parent_tid, &args); + u32 tid = asanThreadRegistry().CreateThread(0, detached, parent_tid, thread); asanThreadRegistry().SetThreadName(tid, name); return thread; @@ -240,6 +237,8 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) { // So this doesn't install any atexit hook like on other platforms. void InstallAtExitCheckLeaks() {} +void InstallAtForkHandler() {} + } // namespace __asan namespace __lsan { diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp index 1b419928c36e..c83b782cb85f 100644 --- a/libsanitizer/asan/asan_globals.cpp +++ b/libsanitizer/asan/asan_globals.cpp @@ -21,31 +21,32 @@ #include "asan_suppressions.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_dense_map.h" +#include "sanitizer_common/sanitizer_list.h" #include "sanitizer_common/sanitizer_mutex.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_symbolizer.h" +#include "sanitizer_common/sanitizer_thread_safety.h" namespace __asan { typedef __asan_global Global; -struct ListOfGlobals { - const Global *g; - ListOfGlobals *next; +struct GlobalListNode { + const Global *g = nullptr; + GlobalListNode *next = nullptr; }; +typedef IntrusiveList ListOfGlobals; static Mutex mu_for_globals; -static ListOfGlobals *list_of_all_globals; +static ListOfGlobals list_of_all_globals SANITIZER_GUARDED_BY(mu_for_globals); -static const int kDynamicInitGlobalsInitialCapacity = 512; struct DynInitGlobal { - Global g; - bool initialized; + Global g = {}; + bool initialized = false; + DynInitGlobal *next = nullptr; }; -typedef InternalMmapVector VectorOfGlobals; -// Lazy-initialized and never deleted. -static VectorOfGlobals *dynamic_init_globals; // We want to remember where a certain range of globals was registered. struct GlobalRegistrationSite { @@ -55,6 +56,39 @@ struct GlobalRegistrationSite { typedef InternalMmapVector GlobalRegistrationSiteVector; static GlobalRegistrationSiteVector *global_registration_site_vector; +static ListOfGlobals &GlobalsByIndicator(uptr odr_indicator) + SANITIZER_REQUIRES(mu_for_globals) { + using MapOfGlobals = DenseMap; + + static MapOfGlobals *globals_by_indicator = nullptr; + if (!globals_by_indicator) { + alignas( + alignof(MapOfGlobals)) static char placeholder[sizeof(MapOfGlobals)]; + globals_by_indicator = new (placeholder) MapOfGlobals(); + } + + return (*globals_by_indicator)[odr_indicator]; +} + +static const char *current_dynamic_init_module_name + SANITIZER_GUARDED_BY(mu_for_globals) = nullptr; + +using DynInitGlobalsByModule = + DenseMap>; + +// TODO: Add a NoDestroy helper, this patter is very common in sanitizers. +static DynInitGlobalsByModule &DynInitGlobals() + SANITIZER_REQUIRES(mu_for_globals) { + static DynInitGlobalsByModule *globals_by_module = nullptr; + if (!globals_by_module) { + alignas(alignof(DynInitGlobalsByModule)) static char + placeholder[sizeof(DynInitGlobalsByModule)]; + globals_by_module = new (placeholder) DynInitGlobalsByModule(); + } + + return *globals_by_module; +} + ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) { FastPoisonShadow(g->beg, g->size_with_redzone, value); } @@ -73,6 +107,35 @@ ALWAYS_INLINE void PoisonRedZones(const Global &g) { const uptr kMinimalDistanceFromAnotherGlobal = 64; +static void AddGlobalToList(ListOfGlobals &list, const Global *g) { + list.push_front(new (GetGlobalLowLevelAllocator()) GlobalListNode{g}); +} + +static void UnpoisonDynamicGlobals(IntrusiveList &dyn_globals, + bool mark_initialized) { + for (auto &dyn_g : dyn_globals) { + const Global *g = &dyn_g.g; + if (dyn_g.initialized) + continue; + // Unpoison the whole global. + PoisonShadowForGlobal(g, 0); + // Poison redzones back. + PoisonRedZones(*g); + if (mark_initialized) + dyn_g.initialized = true; + } +} + +static void PoisonDynamicGlobals( + const IntrusiveList &dyn_globals) { + for (auto &dyn_g : dyn_globals) { + const Global *g = &dyn_g.g; + if (dyn_g.initialized) + continue; + PoisonShadowForGlobal(g, kAsanInitializationOrderMagic); + } +} + static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) { if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false; if (addr >= g.beg + g.size_with_redzone) return false; @@ -114,8 +177,8 @@ int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites, if (!flags()->report_globals) return 0; Lock lock(&mu_for_globals); int res = 0; - for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { - const Global &g = *l->g; + for (const auto &l : list_of_all_globals) { + const Global &g = *l.g; if (flags()->report_globals >= 2) ReportGlobal(g, "Search"); if (IsAddressNearGlobal(addr, g)) { @@ -138,23 +201,47 @@ enum GlobalSymbolState { // Check ODR violation for given global G via special ODR indicator. We use // this method in case compiler instruments global variables through their // local aliases. -static void CheckODRViolationViaIndicator(const Global *g) { +static void CheckODRViolationViaIndicator(const Global *g) + SANITIZER_REQUIRES(mu_for_globals) { // Instrumentation requests to skip ODR check. if (g->odr_indicator == UINTPTR_MAX) return; + + ListOfGlobals &relevant_globals = GlobalsByIndicator(g->odr_indicator); + u8 *odr_indicator = reinterpret_cast(g->odr_indicator); - if (*odr_indicator == UNREGISTERED) { + if (*odr_indicator == REGISTERED) { + // If *odr_indicator is REGISTERED, some module have already registered + // externally visible symbol with the same name. This is an ODR violation. + for (const auto &l : relevant_globals) { + if ((flags()->detect_odr_violation >= 2 || g->size != l.g->size) && + !IsODRViolationSuppressed(g->name)) + ReportODRViolation(g, FindRegistrationSite(g), l.g, + FindRegistrationSite(l.g)); + } + } else { // UNREGISTERED *odr_indicator = REGISTERED; - return; } - // If *odr_indicator is DEFINED, some module have already registered - // externally visible symbol with the same name. This is an ODR violation. - for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { - if (g->odr_indicator == l->g->odr_indicator && - (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && - !IsODRViolationSuppressed(g->name)) - ReportODRViolation(g, FindRegistrationSite(g), - l->g, FindRegistrationSite(l->g)); + + AddGlobalToList(relevant_globals, g); +} + +// Check ODR violation for given global G by checking if it's already poisoned. +// We use this method in case compiler doesn't use private aliases for global +// variables. +static void CheckODRViolationViaPoisoning(const Global *g) + SANITIZER_REQUIRES(mu_for_globals) { + if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) { + // This check may not be enough: if the first global is much larger + // the entire redzone of the second global may be within the first global. + for (const auto &l : list_of_all_globals) { + if (g->beg == l.g->beg && + (flags()->detect_odr_violation >= 2 || g->size != l.g->size) && + !IsODRViolationSuppressed(g->name)) { + ReportODRViolation(g, FindRegistrationSite(g), l.g, + FindRegistrationSite(l.g)); + } + } } } @@ -181,7 +268,7 @@ static inline bool UseODRIndicator(const Global *g) { // Register a global variable. // This function may be called more than once for every global // so we store the globals in a map. -static void RegisterGlobal(const Global *g) { +static void RegisterGlobal(const Global *g) SANITIZER_REQUIRES(mu_for_globals) { CHECK(AsanInited()); if (flags()->report_globals >= 2) ReportGlobal(*g, "Added"); @@ -203,24 +290,22 @@ static void RegisterGlobal(const Global *g) { // where two globals with the same name are defined in different modules. if (UseODRIndicator(g)) CheckODRViolationViaIndicator(g); + else + CheckODRViolationViaPoisoning(g); } if (CanPoisonMemory()) PoisonRedZones(*g); - ListOfGlobals *l = new (GetGlobalLowLevelAllocator()) ListOfGlobals; - l->g = g; - l->next = list_of_all_globals; - list_of_all_globals = l; + + AddGlobalToList(list_of_all_globals, g); + if (g->has_dynamic_init) { - if (!dynamic_init_globals) { - dynamic_init_globals = new (GetGlobalLowLevelAllocator()) VectorOfGlobals; - dynamic_init_globals->reserve(kDynamicInitGlobalsInitialCapacity); - } - DynInitGlobal dyn_global = { *g, false }; - dynamic_init_globals->push_back(dyn_global); + DynInitGlobals()[g->module_name].push_back( + new (GetGlobalLowLevelAllocator()) DynInitGlobal{*g, false}); } } -static void UnregisterGlobal(const Global *g) { +static void UnregisterGlobal(const Global *g) + SANITIZER_REQUIRES(mu_for_globals) { CHECK(AsanInited()); if (flags()->report_globals >= 2) ReportGlobal(*g, "Removed"); @@ -242,18 +327,14 @@ static void UnregisterGlobal(const Global *g) { } void StopInitOrderChecking() { - Lock lock(&mu_for_globals); - if (!flags()->check_initialization_order || !dynamic_init_globals) + if (!flags()->check_initialization_order) return; + Lock lock(&mu_for_globals); flags()->check_initialization_order = false; - for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { - DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; - const Global *g = &dyn_g.g; - // Unpoison the whole global. - PoisonShadowForGlobal(g, 0); - // Poison redzones back. - PoisonRedZones(*g); - } + DynInitGlobals().forEach([&](auto &kv) { + UnpoisonDynamicGlobals(kv.second, /*mark_initialized=*/false); + return true; + }); } static bool IsASCII(unsigned char c) { return /*0x00 <= c &&*/ c <= 0x7F; } @@ -325,8 +406,8 @@ void __asan_unregister_image_globals(uptr *flag) { } void __asan_register_elf_globals(uptr *flag, void *start, void *stop) { - if (*flag) return; - if (!start) return; + if (*flag || start == stop) + return; CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); __asan_global *globals_start = (__asan_global*)start; __asan_global *globals_stop = (__asan_global*)stop; @@ -335,8 +416,8 @@ void __asan_register_elf_globals(uptr *flag, void *start, void *stop) { } void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) { - if (!*flag) return; - if (!start) return; + if (!*flag || start == stop) + return; CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); __asan_global *globals_start = (__asan_global*)start; __asan_global *globals_stop = (__asan_global*)stop; @@ -408,47 +489,94 @@ void __asan_unregister_globals(__asan_global *globals, uptr n) { // poisons all global variables not defined in this TU, so that a dynamic // initializer can only touch global variables in the same TU. void __asan_before_dynamic_init(const char *module_name) { - if (!flags()->check_initialization_order || - !CanPoisonMemory() || - !dynamic_init_globals) + if (!flags()->check_initialization_order || !CanPoisonMemory()) return; bool strict_init_order = flags()->strict_init_order; CHECK(module_name); CHECK(AsanInited()); Lock lock(&mu_for_globals); + if (current_dynamic_init_module_name == module_name) + return; if (flags()->report_globals >= 3) Printf("DynInitPoison module: %s\n", module_name); - for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { - DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; - const Global *g = &dyn_g.g; - if (dyn_g.initialized) - continue; - if (g->module_name != module_name) - PoisonShadowForGlobal(g, kAsanInitializationOrderMagic); - else if (!strict_init_order) - dyn_g.initialized = true; + + if (current_dynamic_init_module_name == nullptr) { + // First call, poison all globals from other modules. + DynInitGlobals().forEach([&](auto &kv) { + if (kv.first != module_name) { + PoisonDynamicGlobals(kv.second); + } else { + UnpoisonDynamicGlobals(kv.second, + /*mark_initialized=*/!strict_init_order); + } + return true; + }); + } else { + // Module changed. + PoisonDynamicGlobals(DynInitGlobals()[current_dynamic_init_module_name]); + UnpoisonDynamicGlobals(DynInitGlobals()[module_name], + /*mark_initialized=*/!strict_init_order); } + current_dynamic_init_module_name = module_name; } +// Maybe SANITIZER_CAN_USE_PREINIT_ARRAY is to conservative for `.init_array`, +// however we should not make mistake here. If `UnpoisonBeforeMain` was not +// executed at all we will have false reports on globals. +#if SANITIZER_CAN_USE_PREINIT_ARRAY +// This optimization aims to reduce the overhead of `__asan_after_dynamic_init` +// calls by leveraging incremental unpoisoning/poisoning in +// `__asan_before_dynamic_init`. We expect most `__asan_after_dynamic_init +// calls` to be no-ops. However, to ensure all globals are unpoisoned before the +// `main`, we force `UnpoisonBeforeMain` to fully execute +// `__asan_after_dynamic_init`. + +// With lld, `UnpoisonBeforeMain` runs after standard `.init_array`, making it +// the final `__asan_after_dynamic_init` call for the static runtime. In +// contrast, GNU ld executes it earlier, causing subsequent +// `__asan_after_dynamic_init` calls to perform full unpoisoning, losing the +// optimization. +bool allow_after_dynamic_init SANITIZER_GUARDED_BY(mu_for_globals) = false; + +static void UnpoisonBeforeMain(void) { + { + Lock lock(&mu_for_globals); + if (allow_after_dynamic_init) + return; + allow_after_dynamic_init = true; + } + if (flags()->report_globals >= 3) + Printf("UnpoisonBeforeMain\n"); + __asan_after_dynamic_init(); +} + +__attribute__((section(".init_array.65537"), used)) static void ( + *asan_after_init_array)(void) = UnpoisonBeforeMain; +#else +// Incremental poisoning is disabled, unpoison globals immediately. +static constexpr bool allow_after_dynamic_init = true; +#endif // SANITIZER_CAN_USE_PREINIT_ARRAY + // This method runs immediately after dynamic initialization in each TU, when // all dynamically initialized globals except for those defined in the current // TU are poisoned. It simply unpoisons all dynamically initialized globals. void __asan_after_dynamic_init() { - if (!flags()->check_initialization_order || - !CanPoisonMemory() || - !dynamic_init_globals) + if (!flags()->check_initialization_order || !CanPoisonMemory()) return; CHECK(AsanInited()); Lock lock(&mu_for_globals); - // FIXME: Optionally report that we're unpoisoning globals from a module. - for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { - DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; - const Global *g = &dyn_g.g; - if (!dyn_g.initialized) { - // Unpoison the whole global. - PoisonShadowForGlobal(g, 0); - // Poison redzones back. - PoisonRedZones(*g); - } - } + if (!allow_after_dynamic_init) + return; + if (!current_dynamic_init_module_name) + return; + + if (flags()->report_globals >= 3) + Printf("DynInitUnpoison\n"); + + DynInitGlobals().forEach([&](auto &kv) { + UnpoisonDynamicGlobals(kv.second, /*mark_initialized=*/false); + return true; + }); + + current_dynamic_init_module_name = nullptr; } diff --git a/libsanitizer/asan/asan_globals_win.cpp b/libsanitizer/asan/asan_globals_win.cpp index 19af88ab12b4..2b59595dcd3b 100644 --- a/libsanitizer/asan/asan_globals_win.cpp +++ b/libsanitizer/asan/asan_globals_win.cpp @@ -17,10 +17,10 @@ namespace __asan { #pragma section(".ASAN$GA", read, write) #pragma section(".ASAN$GZ", read, write) -extern "C" __declspec(allocate(".ASAN$GA")) - ALIGNED(sizeof(__asan_global)) __asan_global __asan_globals_start = {}; -extern "C" __declspec(allocate(".ASAN$GZ")) - ALIGNED(sizeof(__asan_global)) __asan_global __asan_globals_end = {}; +extern "C" alignas(sizeof(__asan_global)) + __declspec(allocate(".ASAN$GA")) __asan_global __asan_globals_start = {}; +extern "C" alignas(sizeof(__asan_global)) + __declspec(allocate(".ASAN$GZ")) __asan_global __asan_globals_end = {}; #pragma comment(linker, "/merge:.ASAN=.data") static void call_on_globals(void (*hook)(__asan_global *, uptr)) { @@ -28,7 +28,9 @@ 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) { -#if defined(SANITIZER_DLL_THUNK) || defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) +# if defined(SANITIZER_DLL_THUNK) || \ + defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || \ + defined(SANITIZER_STATIC_RUNTIME_THUNK) __debugbreak(); #else CHECK("corrupt asan global array"); diff --git a/libsanitizer/asan/asan_interceptors.cpp b/libsanitizer/asan/asan_interceptors.cpp index 635546b525ce..c13bcf2382b0 100644 --- a/libsanitizer/asan/asan_interceptors.cpp +++ b/libsanitizer/asan/asan_interceptors.cpp @@ -96,14 +96,16 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) ASAN_WRITE_RANGE(ctx, ptr, size) #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ ASAN_READ_RANGE(ctx, ptr, size) -# define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ - ASAN_INTERCEPTOR_ENTER(ctx, func); \ - do { \ - if (AsanInitIsRunning()) \ - return REAL(func)(__VA_ARGS__); \ - if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) \ - return REAL(func)(__VA_ARGS__); \ - ENSURE_ASAN_INITED(); \ +# define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ + ASAN_INTERCEPTOR_ENTER(ctx, func); \ + do { \ + if constexpr (SANITIZER_APPLE) { \ + if (UNLIKELY(!AsanInited())) \ + return REAL(func)(__VA_ARGS__); \ + } else { \ + if (!TryAsanInitFromRtl()) \ + return REAL(func)(__VA_ARGS__); \ + } \ } while (false) #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ do { \ @@ -194,10 +196,13 @@ static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) { __lsan::ScopedInterceptorDisabler disabler #endif -#define SIGNAL_INTERCEPTOR_ENTER() ENSURE_ASAN_INITED() +# define SIGNAL_INTERCEPTOR_ENTER() \ + do { \ + AsanInitFromRtl(); \ + } while (false) -#include "sanitizer_common/sanitizer_common_interceptors.inc" -#include "sanitizer_common/sanitizer_signal_interceptors.inc" +# include "sanitizer_common/sanitizer_common_interceptors.inc" +# include "sanitizer_common/sanitizer_signal_interceptors.inc" // Syscall interceptors don't have contexts, we don't support suppressions // for them. @@ -328,7 +333,7 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, } # endif -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS #endif // ASAN_INTERCEPT_PTHREAD_CREATE #if ASAN_INTERCEPT_SWAPCONTEXT @@ -506,7 +511,7 @@ DEFINE_REAL(char*, index, const char *string, int c) INTERCEPTOR(char *, strcat, char *to, const char *from) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strcat); - ENSURE_ASAN_INITED(); + AsanInitFromRtl(); if (flags()->replace_str) { uptr from_length = internal_strlen(from); ASAN_READ_RANGE(ctx, from, from_length + 1); @@ -527,7 +532,7 @@ DEFINE_REAL(char*, index, const char *string, int c) INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strncat); - ENSURE_ASAN_INITED(); + AsanInitFromRtl(); if (flags()->replace_str) { uptr from_length = MaybeRealStrnlen(from, size); uptr copy_length = Min(size, from_length + 1); @@ -546,16 +551,16 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { INTERCEPTOR(char *, strcpy, char *to, const char *from) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strcpy); -#if SANITIZER_APPLE - if (UNLIKELY(!AsanInited())) - return REAL(strcpy)(to, from); -#endif - // strcpy is called from malloc_default_purgeable_zone() - // in __asan::ReplaceSystemAlloc() on Mac. - if (AsanInitIsRunning()) { - return REAL(strcpy)(to, from); + if constexpr (SANITIZER_APPLE) { + // strcpy is called from malloc_default_purgeable_zone() + // in __asan::ReplaceSystemAlloc() on Mac. + if (UNLIKELY(!AsanInited())) + return REAL(strcpy)(to, from); + } else { + if (!TryAsanInitFromRtl()) + return REAL(strcpy)(to, from); } - ENSURE_ASAN_INITED(); + if (flags()->replace_str) { uptr from_size = internal_strlen(from) + 1; CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size); @@ -565,12 +570,22 @@ INTERCEPTOR(char *, strcpy, char *to, const char *from) { return REAL(strcpy)(to, from); } +// Windows doesn't always define the strdup identifier, +// and when it does it's a macro defined to either _strdup +// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so +// we want to intercept that. push/pop_macro are used to avoid problems +// if this file ends up including in the future. +# if SANITIZER_WINDOWS +# pragma push_macro("strdup") +# undef strdup +# define strdup _strdup +# endif + INTERCEPTOR(char*, strdup, const char *s) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strdup); - if (UNLIKELY(!AsanInited())) + if (UNLIKELY(!TryAsanInitFromRtl())) return internal_strdup(s); - ENSURE_ASAN_INITED(); uptr length = internal_strlen(s); if (flags()->replace_str) { ASAN_READ_RANGE(ctx, s, length + 1); @@ -583,13 +598,12 @@ INTERCEPTOR(char*, strdup, const char *s) { return reinterpret_cast(new_mem); } -#if ASAN_INTERCEPT___STRDUP +# if ASAN_INTERCEPT___STRDUP INTERCEPTOR(char*, __strdup, const char *s) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strdup); - if (UNLIKELY(!AsanInited())) + if (UNLIKELY(!TryAsanInitFromRtl())) return internal_strdup(s); - ENSURE_ASAN_INITED(); uptr length = internal_strlen(s); if (flags()->replace_str) { ASAN_READ_RANGE(ctx, s, length + 1); @@ -606,7 +620,7 @@ INTERCEPTOR(char*, __strdup, const char *s) { INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strncpy); - ENSURE_ASAN_INITED(); + AsanInitFromRtl(); if (flags()->replace_str) { uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1); CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size); @@ -632,13 +646,38 @@ static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr, INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \ void *ctx; \ ASAN_INTERCEPTOR_ENTER(ctx, func); \ - ENSURE_ASAN_INITED(); \ + AsanInitFromRtl(); \ return StrtolImpl(ctx, REAL(func), nptr, endptr, base); \ } -INTERCEPTOR_STRTO_BASE(long, strtol) INTERCEPTOR_STRTO_BASE(long long, strtoll) +# if SANITIZER_WINDOWS +INTERCEPTOR(long, strtol, const char *nptr, char **endptr, int base) { + // REAL(strtol) may be ntdll!strtol, which doesn't set errno. Instead, + // call REAL(strtoll) and do the range check ourselves. + COMPILER_CHECK(sizeof(long) == sizeof(u32)); + + void *ctx; + ASAN_INTERCEPTOR_ENTER(ctx, strtol); + AsanInitFromRtl(); + + long long result = StrtolImpl(ctx, REAL(strtoll), nptr, endptr, base); + + if (result > INT32_MAX) { + errno = errno_ERANGE; + return INT32_MAX; + } + if (result < INT32_MIN) { + errno = errno_ERANGE; + return INT32_MIN; + } + return (long)result; +} +# else +INTERCEPTOR_STRTO_BASE(long, strtol) +# endif + # if SANITIZER_GLIBC INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol) INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll) @@ -647,11 +686,9 @@ INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll) INTERCEPTOR(int, atoi, const char *nptr) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, atoi); -#if SANITIZER_APPLE - if (UNLIKELY(!AsanInited())) + if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) return REAL(atoi)(nptr); -# endif - ENSURE_ASAN_INITED(); + AsanInitFromRtl(); if (!flags()->replace_str) { return REAL(atoi)(nptr); } @@ -669,11 +706,9 @@ INTERCEPTOR(int, atoi, const char *nptr) { INTERCEPTOR(long, atol, const char *nptr) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, atol); -#if SANITIZER_APPLE - if (UNLIKELY(!AsanInited())) + if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) return REAL(atol)(nptr); -# endif - ENSURE_ASAN_INITED(); + AsanInitFromRtl(); if (!flags()->replace_str) { return REAL(atol)(nptr); } @@ -687,7 +722,7 @@ INTERCEPTOR(long, atol, const char *nptr) { INTERCEPTOR(long long, atoll, const char *nptr) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, atoll); - ENSURE_ASAN_INITED(); + AsanInitFromRtl(); if (!flags()->replace_str) { return REAL(atoll)(nptr); } @@ -708,12 +743,10 @@ static void AtCxaAtexit(void *unused) { #if ASAN_INTERCEPT___CXA_ATEXIT INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, void *dso_handle) { -#if SANITIZER_APPLE - if (UNLIKELY(!AsanInited())) + if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) return REAL(__cxa_atexit)(func, arg, dso_handle); -# endif - ENSURE_ASAN_INITED(); -#if CAN_SANITIZE_LEAKS + AsanInitFromRtl(); +# if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler disabler; #endif int res = REAL(__cxa_atexit)(func, arg, dso_handle); @@ -724,8 +757,8 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, #if ASAN_INTERCEPT_ATEXIT INTERCEPTOR(int, atexit, void (*func)()) { - ENSURE_ASAN_INITED(); -#if CAN_SANITIZE_LEAKS + AsanInitFromRtl(); +# if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler disabler; #endif // Avoid calling real atexit as it is unreachable on at least on Linux. @@ -739,7 +772,7 @@ INTERCEPTOR(int, atexit, void (*func)()) { extern "C" { extern int _pthread_atfork(void (*prepare)(), void (*parent)(), void (*child)()); -}; +} INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), void (*child)()) { @@ -753,8 +786,8 @@ INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), #endif #if ASAN_INTERCEPT_VFORK -DEFINE_REAL(int, vfork) -DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork) +DEFINE_REAL(int, vfork,) +DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,) #endif // ---------------------- InitializeAsanInterceptors ---------------- {{{1 @@ -773,7 +806,7 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(strncat); ASAN_INTERCEPT_FUNC(strncpy); ASAN_INTERCEPT_FUNC(strdup); -#if ASAN_INTERCEPT___STRDUP +# if ASAN_INTERCEPT___STRDUP ASAN_INTERCEPT_FUNC(__strdup); #endif #if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX @@ -869,6 +902,10 @@ void InitializeAsanInterceptors() { VReport(1, "AddressSanitizer: libc interceptors initialized\n"); } +# if SANITIZER_WINDOWS +# pragma pop_macro("strdup") +# endif + } // namespace __asan #endif // !SANITIZER_FUCHSIA diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h index 8e9ed5d1ef4e..826b45f5ada8 100644 --- a/libsanitizer/asan/asan_interceptors.h +++ b/libsanitizer/asan/asan_interceptors.h @@ -24,14 +24,6 @@ namespace __asan { void InitializeAsanInterceptors(); void InitializePlatformInterceptors(); -#define ENSURE_ASAN_INITED() \ - do { \ - CHECK(!AsanInitIsRunning()); \ - if (UNLIKELY(!AsanInited())) { \ - AsanInitFromRtl(); \ - } \ - } while (0) - } // namespace __asan // There is no general interception at all on Fuchsia. @@ -79,12 +71,7 @@ void InitializePlatformInterceptors(); #if ASAN_HAS_EXCEPTIONS && !SANITIZER_SOLARIS && !SANITIZER_NETBSD && \ (!SANITIZER_WINDOWS || (defined(__MINGW32__) && defined(__i386__))) # define ASAN_INTERCEPT___CXA_THROW 1 -# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \ - || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 -# else -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0 -# endif +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 # if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__)) # define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1 # else diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h index e2b1e9800f5b..06dfc4b17733 100644 --- a/libsanitizer/asan/asan_internal.h +++ b/libsanitizer/asan/asan_internal.h @@ -60,6 +60,7 @@ class AsanThread; using __sanitizer::StackTrace; void AsanInitFromRtl(); +bool TryAsanInitFromRtl(); // asan_win.cpp void InitializePlatformExceptionHandlers(); @@ -79,7 +80,6 @@ void ReplaceSystemMalloc(); // asan_linux.cpp / asan_mac.cpp / asan_win.cpp uptr FindDynamicShadowStart(); -void *AsanDoesNotSupportStaticLinkage(); void AsanCheckDynamicRTPrereqs(); void AsanCheckIncompatibleRT(); @@ -125,13 +125,13 @@ void *AsanDlSymNext(const char *sym); bool HandleDlopenInit(); void InstallAtExitCheckLeaks(); +void InstallAtForkHandler(); #define ASAN_ON_ERROR() \ if (&__asan_on_error) \ __asan_on_error() bool AsanInited(); -bool AsanInitIsRunning(); // Used to avoid infinite recursion in __asan_init(). extern bool replace_intrin_cached; extern void (*death_callback)(void); // These magic values are written to shadow for better error diff --git a/libsanitizer/asan/asan_linux.cpp b/libsanitizer/asan/asan_linux.cpp index e19b4479aaf3..4cabca388ca9 100644 --- a/libsanitizer/asan/asan_linux.cpp +++ b/libsanitizer/asan/asan_linux.cpp @@ -33,7 +33,6 @@ # include "asan_premap_shadow.h" # include "asan_thread.h" # include "sanitizer_common/sanitizer_flags.h" -# include "sanitizer_common/sanitizer_freebsd.h" # include "sanitizer_common/sanitizer_hash.h" # include "sanitizer_common/sanitizer_libc.h" # include "sanitizer_common/sanitizer_procmaps.h" @@ -48,22 +47,12 @@ # if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS # include -extern "C" void *_DYNAMIC; # elif SANITIZER_NETBSD # include # include -extern Elf_Dyn _DYNAMIC; # else # include # include -extern ElfW(Dyn) _DYNAMIC[]; -# endif - -// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in -// 32-bit mode. -# if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \ - __FreeBSD_version <= 902001 // v9.2 -# define ucontext_t xucontext_t # endif typedef enum { @@ -84,11 +73,6 @@ void InitializePlatformInterceptors() {} void InitializePlatformExceptionHandlers() {} bool IsSystemHeapAddress(uptr addr) { return false; } -void *AsanDoesNotSupportStaticLinkage() { - // This will fail to link with -static. - return &_DYNAMIC; -} - # if ASAN_PREMAP_SHADOW uptr FindPremappedShadowStart(uptr shadow_size_bytes) { uptr granularity = GetMmapGranularity(); @@ -109,7 +93,8 @@ uptr FindDynamicShadowStart() { # endif return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE, - /*min_shadow_base_alignment*/ 0, kHighMemEnd); + /*min_shadow_base_alignment*/ 0, kHighMemEnd, + GetMmapGranularity()); } void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { @@ -148,6 +133,11 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0) return 0; # endif +# if SANITIZER_FREEBSD + // Ignore vDSO. + if (internal_strcmp(info->dlpi_name, "[vdso]") == 0) + return 0; +# endif *name = info->dlpi_name; return 1; @@ -197,10 +187,7 @@ void AsanCheckIncompatibleRT() { MemoryMappedSegment segment(filename, sizeof(filename)); while (proc_maps.Next(&segment)) { if (IsDynamicRTName(segment.filename)) { - Report( - "Your application is linked against " - "incompatible ASan runtimes.\n"); - Die(); + ReportIncompatibleRT(); } } __asan_rt_version = ASAN_RT_VERSION_STATIC; diff --git a/libsanitizer/asan/asan_lock.h b/libsanitizer/asan/asan_lock.h deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/libsanitizer/asan/asan_mac.cpp b/libsanitizer/asan/asan_mac.cpp index 6252fa20d5e7..bfc349223258 100644 --- a/libsanitizer/asan/asan_mac.cpp +++ b/libsanitizer/asan/asan_mac.cpp @@ -49,14 +49,10 @@ void InitializePlatformInterceptors() {} void InitializePlatformExceptionHandlers() {} bool IsSystemHeapAddress (uptr addr) { return false; } -// No-op. Mac does not support static linkage anyway. -void *AsanDoesNotSupportStaticLinkage() { - return 0; -} - uptr FindDynamicShadowStart() { return MapDynamicShadow(MemToShadowSize(kHighMemEnd), ASAN_SHADOW_SCALE, - /*min_shadow_base_alignment*/ 0, kHighMemEnd); + /*min_shadow_base_alignment*/ 0, kHighMemEnd, + GetMmapGranularity()); } // No-op. Mac does not support static linkage anyway. @@ -139,11 +135,11 @@ typedef void (*dispatch_mach_handler_function_t)(void *context, dispatch_mach_reason reason, dispatch_mach_msg_t message, mach_error_t error); -#if !defined(MISSING_BLOCKS_SUPPORT) +# if !defined(MISSING_BLOCKS_SUPPORT) typedef void (^dispatch_mach_handler_t)(dispatch_mach_reason reason, dispatch_mach_msg_t message, mach_error_t error); -#endif +# endif // A wrapper for the ObjC blocks used to support libdispatch. typedef struct { diff --git a/libsanitizer/asan/asan_malloc_linux.cpp b/libsanitizer/asan/asan_malloc_linux.cpp index 0ba74c5d7143..3d6b03fefab7 100644 --- a/libsanitizer/asan/asan_malloc_linux.cpp +++ b/libsanitizer/asan/asan_malloc_linux.cpp @@ -25,13 +25,12 @@ # include "sanitizer_common/sanitizer_allocator_checks.h" # include "sanitizer_common/sanitizer_allocator_dlsym.h" # include "sanitizer_common/sanitizer_errno.h" -# include "sanitizer_common/sanitizer_tls_get_addr.h" // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; struct DlsymAlloc : public DlSymAllocator { - static bool UseImpl() { return AsanInitIsRunning(); } + static bool UseImpl() { return !TryAsanInitFromRtl(); } static void OnAllocate(const void *ptr, uptr size) { # if CAN_SANITIZE_LEAKS // Suppress leaks from dlerror(). Previously dlsym hack on global array was @@ -65,7 +64,6 @@ INTERCEPTOR(void, cfree, void *ptr) { INTERCEPTOR(void*, malloc, uptr size) { if (DlsymAlloc::Use()) return DlsymAlloc::Allocate(size); - ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } @@ -73,7 +71,6 @@ INTERCEPTOR(void*, malloc, uptr size) { INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { if (DlsymAlloc::Use()) return DlsymAlloc::Callocate(nmemb, size); - ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } @@ -81,14 +78,13 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { INTERCEPTOR(void*, realloc, void *ptr, uptr size) { if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) return DlsymAlloc::Realloc(ptr, size); - ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } #if SANITIZER_INTERCEPT_REALLOCARRAY INTERCEPTOR(void*, reallocarray, void *ptr, uptr nmemb, uptr size) { - ENSURE_ASAN_INITED(); + AsanInitFromRtl(); GET_STACK_TRACE_MALLOC; return asan_reallocarray(ptr, nmemb, size, &stack); } @@ -102,9 +98,7 @@ INTERCEPTOR(void*, memalign, uptr boundary, uptr size) { INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; - void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC); - DTLS_on_libc_memalign(res, size); - return res; + return asan_memalign(boundary, size, &stack, FROM_MALLOC); } #endif // SANITIZER_INTERCEPT_MEMALIGN @@ -188,11 +182,11 @@ struct MallocDebugL { void* (*valloc)(uptr size); }; -ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = { +alignas(32) const MallocDebugK asan_malloc_dispatch_k = { WRAP(malloc), WRAP(free), WRAP(calloc), WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)}; -ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = { +alignas(32) const MallocDebugL asan_malloc_dispatch_l = { WRAP(calloc), WRAP(free), WRAP(mallinfo), WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign), WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc), diff --git a/libsanitizer/asan/asan_malloc_mac.cpp b/libsanitizer/asan/asan_malloc_mac.cpp index d2380ee62bf3..f25d7e190153 100644 --- a/libsanitizer/asan/asan_malloc_mac.cpp +++ b/libsanitizer/asan/asan_malloc_mac.cpp @@ -22,7 +22,10 @@ using namespace __asan; #define COMMON_MALLOC_ZONE_NAME "asan" -#define COMMON_MALLOC_ENTER() ENSURE_ASAN_INITED() +# define COMMON_MALLOC_ENTER() \ + do { \ + AsanInitFromRtl(); \ + } while (false) # define COMMON_MALLOC_SANITIZER_INITIALIZED AsanInited() # define COMMON_MALLOC_FORCE_LOCK() asan_mz_force_lock() # define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock() diff --git a/libsanitizer/asan/asan_malloc_win.cpp b/libsanitizer/asan/asan_malloc_win.cpp index 7e1d04c36dd5..3278f0721987 100644 --- a/libsanitizer/asan/asan_malloc_win.cpp +++ b/libsanitizer/asan/asan_malloc_win.cpp @@ -58,97 +58,69 @@ using namespace __asan; // MD: Memory allocation functions are defined in the CRT .dll, // so we have to intercept them before they are called for the first time. -#if ASAN_DYNAMIC -# define ALLOCATION_FUNCTION_ATTRIBUTE -#else -# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE -#endif - extern "C" { -ALLOCATION_FUNCTION_ATTRIBUTE -size_t _msize(void *ptr) { +__declspec(noinline) 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); -} +__declspec(noinline) size_t _msize_base(void *ptr) { return _msize(ptr); } -ALLOCATION_FUNCTION_ATTRIBUTE -void free(void *ptr) { +__declspec(noinline) void free(void *ptr) { GET_STACK_TRACE_FREE; return asan_free(ptr, &stack, FROM_MALLOC); } -ALLOCATION_FUNCTION_ATTRIBUTE -void _free_dbg(void *ptr, int) { - free(ptr); -} +__declspec(noinline) void _free_dbg(void *ptr, int) { free(ptr); } -ALLOCATION_FUNCTION_ATTRIBUTE -void _free_base(void *ptr) { - free(ptr); -} +__declspec(noinline) void _free_base(void *ptr) { free(ptr); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *malloc(size_t size) { +__declspec(noinline) void *malloc(size_t size) { GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_malloc_base(size_t size) { - return malloc(size); -} +__declspec(noinline) void *_malloc_base(size_t size) { return malloc(size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_malloc_dbg(size_t size, int, const char *, int) { +__declspec(noinline) void *_malloc_dbg(size_t size, int, const char *, int) { return malloc(size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *calloc(size_t nmemb, size_t size) { +__declspec(noinline) void *calloc(size_t nmemb, size_t size) { GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_calloc_base(size_t nmemb, size_t size) { +__declspec(noinline) void *_calloc_base(size_t nmemb, size_t size) { return calloc(nmemb, size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) { +__declspec(noinline) void *_calloc_dbg(size_t nmemb, size_t size, int, + const char *, int) { return calloc(nmemb, size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) { +__declspec(noinline) void *_calloc_impl(size_t nmemb, size_t size, + int *errno_tmp) { return calloc(nmemb, size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *realloc(void *ptr, size_t size) { +__declspec(noinline) void *realloc(void *ptr, size_t size) { GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_realloc_dbg(void *ptr, size_t size, int) { +__declspec(noinline) void *_realloc_dbg(void *ptr, size_t size, int) { UNREACHABLE("_realloc_dbg should not exist!"); return 0; } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_realloc_base(void *ptr, size_t size) { +__declspec(noinline) void *_realloc_base(void *ptr, size_t size) { return realloc(ptr, size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_recalloc(void *p, size_t n, size_t elem_size) { +__declspec(noinline) void *_recalloc(void *p, size_t n, size_t elem_size) { if (!p) return calloc(n, elem_size); const size_t size = n * elem_size; @@ -166,23 +138,41 @@ void *_recalloc(void *p, size_t n, size_t elem_size) { return new_alloc; } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_recalloc_base(void *p, size_t n, size_t elem_size) { +__declspec(noinline) void *_recalloc_base(void *p, size_t n, size_t elem_size) { return _recalloc(p, n, elem_size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_expand(void *memblock, size_t size) { +__declspec(noinline) void *_expand(void *memblock, size_t size) { // _expand is used in realloc-like functions to resize the buffer if possible. // We don't want memory to stand still while resizing buffers, so return 0. return 0; } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_expand_dbg(void *memblock, size_t size) { +__declspec(noinline) void *_expand_dbg(void *memblock, size_t size) { return _expand(memblock, size); } +__declspec(dllexport) size_t __cdecl __asan_msize(void *ptr) { + return _msize(ptr); +} +__declspec(dllexport) void __cdecl __asan_free(void *const ptr) { free(ptr); } +__declspec(dllexport) void *__cdecl __asan_malloc(const size_t size) { + return malloc(size); +} +__declspec(dllexport) void *__cdecl __asan_calloc(const size_t nmemb, + const size_t size) { + return calloc(nmemb, size); +} +__declspec(dllexport) void *__cdecl __asan_realloc(void *const ptr, + const size_t size) { + return realloc(ptr, size); +} +__declspec(dllexport) void *__cdecl __asan_recalloc(void *const ptr, + const size_t nmemb, + const size_t size) { + return _recalloc(ptr, nmemb, size); +} + // TODO(timurrrr): Might want to add support for _aligned_* allocation // functions to detect a bit more bugs. Those functions seem to wrap malloc(). @@ -487,7 +477,6 @@ static void TryToOverrideFunction(const char *fname, uptr new_func) { } void ReplaceSystemMalloc() { -#if defined(ASAN_DYNAMIC) TryToOverrideFunction("free", (uptr)free); TryToOverrideFunction("_free_base", (uptr)free); TryToOverrideFunction("malloc", (uptr)malloc); @@ -543,8 +532,6 @@ void ReplaceSystemMalloc() { // allocation API will be directed to ASan's heap. We don't currently // intercept all calls to HeapAlloc. If we did, we would have to check on // HeapFree whether the pointer came from ASan of from the system. - -#endif // defined(ASAN_DYNAMIC) } } // namespace __asan diff --git a/libsanitizer/asan/asan_malloc_win_thunk.cpp b/libsanitizer/asan/asan_malloc_win_thunk.cpp new file mode 100644 index 000000000000..9cc00913177e --- /dev/null +++ b/libsanitizer/asan/asan_malloc_win_thunk.cpp @@ -0,0 +1,229 @@ +//===-- asan_malloc_win_thunk.cpp +//-----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Windows-specific malloc interception. +// This is included statically for projects statically linking +// with the C Runtime (/MT, /MTd) in order to provide ASAN-aware +// versions of the C allocation functions. +//===----------------------------------------------------------------------===// + +#ifdef SANITIZER_STATIC_RUNTIME_THUNK +# include "..\sanitizer_common\sanitizer_allocator_interface.h" +// #include "asan_win_thunk_common.h" + +// Preserve stack traces with noinline. +# define STATIC_MALLOC_INTERFACE __declspec(noinline) + +extern "C" { +__declspec(dllimport) size_t __cdecl __asan_msize(void *ptr); +__declspec(dllimport) void __cdecl __asan_free(void *const ptr); +__declspec(dllimport) void *__cdecl __asan_malloc(const size_t size); +__declspec(dllimport) void *__cdecl __asan_calloc(const size_t nmemb, + const size_t size); +__declspec(dllimport) void *__cdecl __asan_realloc(void *const ptr, + const size_t size); +__declspec(dllimport) void *__cdecl __asan_recalloc(void *const ptr, + const size_t nmemb, + const size_t size); + +// Avoid tailcall optimization to preserve stack frames. +# pragma optimize("", off) + +// _msize +STATIC_MALLOC_INTERFACE size_t _msize(void *ptr) { return __asan_msize(ptr); } + +STATIC_MALLOC_INTERFACE size_t _msize_base(void *ptr) { + return __asan_msize(ptr); +} + +STATIC_MALLOC_INTERFACE size_t _msize_dbg(void *ptr) { + return __asan_msize(ptr); +} + +// free +STATIC_MALLOC_INTERFACE void free(void *const ptr) { return __asan_free(ptr); } + +STATIC_MALLOC_INTERFACE void _free_base(void *const ptr) { + return __asan_free(ptr); +} + +STATIC_MALLOC_INTERFACE void _free_dbg(void *const ptr) { + return __asan_free(ptr); +} + +// malloc +STATIC_MALLOC_INTERFACE void *malloc(const size_t size) { + return __asan_malloc(size); +} + +STATIC_MALLOC_INTERFACE void *_malloc_base(const size_t size) { + return __asan_malloc(size); +} + +STATIC_MALLOC_INTERFACE void *_malloc_dbg(const size_t size) { + return __asan_malloc(size); +} + +// calloc +STATIC_MALLOC_INTERFACE void *calloc(const size_t nmemb, const size_t size) { + return __asan_calloc(nmemb, size); +} + +STATIC_MALLOC_INTERFACE void *_calloc_base(const size_t nmemb, + const size_t size) { + return __asan_calloc(nmemb, size); +} + +STATIC_MALLOC_INTERFACE void *_calloc_impl(const size_t nmemb, + const size_t size, + int *const errno_tmp) { + // Provided by legacy msvcrt. + (void)errno_tmp; + + return __asan_calloc(nmemb, size); +} + +STATIC_MALLOC_INTERFACE void *_calloc_dbg(const size_t nmemb, const size_t size, + int, const char *, int) { + return __asan_calloc(nmemb, size); +} + +// realloc +STATIC_MALLOC_INTERFACE void *realloc(void *const ptr, const size_t size) { + return __asan_realloc(ptr, size); +} + +STATIC_MALLOC_INTERFACE void *_realloc_base(void *const ptr, + const size_t size) { + return __asan_realloc(ptr, size); +} + +STATIC_MALLOC_INTERFACE void *_realloc_dbg(void *const ptr, const size_t size, + int, const char *, int) { + return __asan_realloc(ptr, size); +} + +// recalloc +STATIC_MALLOC_INTERFACE void *_recalloc(void *const ptr, const size_t nmemb, + const size_t size) { + return __asan_recalloc(ptr, nmemb, size); +} + +STATIC_MALLOC_INTERFACE void *_recalloc_base(void *const ptr, + const size_t nmemb, + const size_t size) { + return __asan_recalloc(ptr, nmemb, size); +} + +STATIC_MALLOC_INTERFACE void *_recalloc_dbg(void *const ptr, const size_t nmemb, + const size_t size, int, + const char *, int) { + return __asan_recalloc(ptr, nmemb, size); +} + +// expand +STATIC_MALLOC_INTERFACE void *_expand(void *, size_t) { + // _expand is used in realloc-like functions to resize the buffer if possible. + // We don't want memory to stand still while resizing buffers, so return 0. + return nullptr; +} + +STATIC_MALLOC_INTERFACE void *_expand_dbg(void *, size_t, int, const char *, + int) { + return nullptr; +} + +// We need to provide symbols for all the debug CRT functions if we decide to +// provide any. Most of these functions make no sense under ASan and so we +// make them no-ops. +long _CrtSetBreakAlloc(long const) { return ~0; } + +void _CrtSetDbgBlockType(void *const, int const) { return; } + +typedef int(__cdecl *CRT_ALLOC_HOOK)(int, void *, size_t, int, long, + const unsigned char *, int); + +CRT_ALLOC_HOOK _CrtGetAllocHook() { return nullptr; } + +CRT_ALLOC_HOOK _CrtSetAllocHook(CRT_ALLOC_HOOK const hook) { return hook; } + +int _CrtCheckMemory() { return 1; } + +int _CrtSetDbgFlag(int const new_bits) { return new_bits; } + +typedef void (*CrtDoForAllClientObjectsCallback)(void *, void *); + +void _CrtDoForAllClientObjects(CrtDoForAllClientObjectsCallback const, + void *const) { + return; +} + +int _CrtIsValidPointer(void const *const p, unsigned int const, int const) { + return p != nullptr; +} + +int _CrtIsValidHeapPointer(void const *const block) { + if (!block) { + return 0; + } + + return __sanitizer_get_ownership(block); +} + +int _CrtIsMemoryBlock(void const *const, unsigned const, long *const, + char **const, int *const) { + return 0; +} + +int _CrtReportBlockType(void const *const) { return -1; } + +typedef void(__cdecl *CRT_DUMP_CLIENT)(void *, size_t); + +CRT_DUMP_CLIENT _CrtGetDumpClient() { return nullptr; } + +CRT_DUMP_CLIENT _CrtSetDumpClient(CRT_DUMP_CLIENT new_client) { + return new_client; +} + +void _CrtMemCheckpoint(void *const) { return; } + +int _CrtMemDifference(void *const, void const *const, void const *const) { + return 0; +} + +void _CrtMemDumpAllObjectsSince(void const *const) { return; } + +int _CrtDumpMemoryLeaks() { return 0; } + +void _CrtMemDumpStatistics(void const *const) { return; } + +int _crtDbgFlag{0}; +long _crtBreakAlloc{-1}; +CRT_DUMP_CLIENT _pfnDumpClient{nullptr}; + +int *__p__crtDbgFlag() { return &_crtDbgFlag; } + +long *__p__crtBreakAlloc() { return &_crtBreakAlloc; } + +// TODO: These were added upstream but conflict with definitions in ucrtbased. +// int _CrtDbgReport(int, const char *, int, const char *, const char *, ...) { +// ShowStatsAndAbort(); +// } +// +// int _CrtDbgReportW(int reportType, const wchar_t *, int, const wchar_t *, +// const wchar_t *, ...) { +// ShowStatsAndAbort(); +// } +// +// int _CrtSetReportMode(int, int) { return 0; } + +} // extern "C" +#endif // SANITIZER_STATIC_RUNTIME_THUNK diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h index 47ccf8444d31..91fe60db6329 100644 --- a/libsanitizer/asan/asan_mapping.h +++ b/libsanitizer/asan/asan_mapping.h @@ -72,7 +72,10 @@ // || `[0x2000000000, 0x23ffffffff]` || LowShadow || // || `[0x0000000000, 0x1fffffffff]` || LowMem || // -// Default Linux/RISCV64 Sv39 mapping: +// Default Linux/RISCV64 Sv39 mapping with SHADOW_OFFSET == 0xd55550000; +// (the exact location of SHADOW_OFFSET may vary depending the dynamic probing +// by FindDynamicShadowStart). +// // || `[0x1555550000, 0x3fffffffff]` || HighMem || // || `[0x0fffffa000, 0x1555555fff]` || HighShadow || // || `[0x0effffa000, 0x0fffff9fff]` || ShadowGap || @@ -186,11 +189,11 @@ # elif SANITIZER_FREEBSD && defined(__aarch64__) # define ASAN_SHADOW_OFFSET_CONST 0x0000800000000000 # elif SANITIZER_RISCV64 -# define ASAN_SHADOW_OFFSET_CONST 0x0000000d55550000 +# define ASAN_SHADOW_OFFSET_DYNAMIC # elif defined(__aarch64__) # define ASAN_SHADOW_OFFSET_CONST 0x0000001000000000 # elif defined(__powerpc64__) -# define ASAN_SHADOW_OFFSET_CONST 0x0000020000000000 +# define ASAN_SHADOW_OFFSET_CONST 0x0000100000000000 # elif defined(__s390x__) # define ASAN_SHADOW_OFFSET_CONST 0x0010000000000000 # elif SANITIZER_FREEBSD diff --git a/libsanitizer/asan/asan_new_delete.cpp b/libsanitizer/asan/asan_new_delete.cpp index 17280129c758..b5b1ced8ac5e 100644 --- a/libsanitizer/asan/asan_new_delete.cpp +++ b/libsanitizer/asan/asan_new_delete.cpp @@ -48,15 +48,6 @@ COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[] using namespace __asan; -// FreeBSD prior v9.2 have wrong definition of 'size_t'. -// http://svnweb.freebsd.org/base?view=revision&revision=232261 -#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32 -#include -#if __FreeBSD_version <= 902001 // v9.2 -#define size_t unsigned -#endif // __FreeBSD_version -#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32 - // This code has issues on OSX. // See https://github.com/google/sanitizers/issues/131. diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp index 746ad61813c6..762670632f4e 100644 --- a/libsanitizer/asan/asan_poisoning.cpp +++ b/libsanitizer/asan/asan_poisoning.cpp @@ -16,6 +16,7 @@ #include "asan_report.h" #include "asan_stack.h" #include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_interface_internal.h" #include "sanitizer_common/sanitizer_libc.h" @@ -410,7 +411,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p, const void *new_mid_p) { if (!flags()->detect_container_overflow) return; - VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p, + VPrintf(3, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p, new_mid_p); uptr storage_beg = reinterpret_cast(beg_p); uptr storage_end = reinterpret_cast(end_p); @@ -479,7 +480,7 @@ void __sanitizer_annotate_double_ended_contiguous_container( if (!flags()->detect_container_overflow) return; - VPrintf(2, "contiguous_container: %p %p %p %p %p %p\n", storage_beg_p, + VPrintf(3, "contiguous_container: %p %p %p %p %p %p\n", storage_beg_p, storage_end_p, old_container_beg_p, old_container_end_p, new_container_beg_p, new_container_end_p); @@ -576,6 +577,185 @@ void __sanitizer_annotate_double_ended_contiguous_container( } } +// Marks the specified number of bytes in a granule as accessible or +// poisones the whole granule with kAsanContiguousContainerOOBMagic value. +static void SetContainerGranule(uptr ptr, u8 n) { + constexpr uptr granularity = ASAN_SHADOW_GRANULARITY; + u8 s = (n == granularity) ? 0 : (n ? n : kAsanContiguousContainerOOBMagic); + *(u8 *)MemToShadow(ptr) = s; +} + +// Performs a byte-by-byte copy of ASan annotations (shadow memory values). +// Result may be different due to ASan limitations, but result cannot lead +// to false positives (more memory than requested may get unpoisoned). +static void SlowCopyContainerAnnotations(uptr src_beg, uptr src_end, + uptr dst_beg, uptr dst_end) { + constexpr uptr granularity = ASAN_SHADOW_GRANULARITY; + uptr dst_end_down = RoundDownTo(dst_end, granularity); + uptr src_ptr = src_beg; + uptr dst_ptr = dst_beg; + + while (dst_ptr < dst_end) { + uptr granule_beg = RoundDownTo(dst_ptr, granularity); + uptr granule_end = granule_beg + granularity; + uptr unpoisoned_bytes = 0; + + uptr end = Min(granule_end, dst_end); + for (; dst_ptr != end; ++dst_ptr, ++src_ptr) + if (!AddressIsPoisoned(src_ptr)) + unpoisoned_bytes = dst_ptr - granule_beg + 1; + + if (dst_ptr == dst_end && dst_end != dst_end_down && + !AddressIsPoisoned(dst_end)) + continue; + + if (unpoisoned_bytes != 0 || granule_beg >= dst_beg) + SetContainerGranule(granule_beg, unpoisoned_bytes); + else if (!AddressIsPoisoned(dst_beg)) + SetContainerGranule(granule_beg, dst_beg - granule_beg); + } +} + +// Performs a byte-by-byte copy of ASan annotations (shadow memory values), +// going through bytes in reversed order, but not reversing annotations. +// Result may be different due to ASan limitations, but result cannot lead +// to false positives (more memory than requested may get unpoisoned). +static void SlowReversedCopyContainerAnnotations(uptr src_beg, uptr src_end, + uptr dst_beg, uptr dst_end) { + constexpr uptr granularity = ASAN_SHADOW_GRANULARITY; + uptr dst_end_down = RoundDownTo(dst_end, granularity); + uptr src_ptr = src_end; + uptr dst_ptr = dst_end; + + while (dst_ptr > dst_beg) { + uptr granule_beg = RoundDownTo(dst_ptr - 1, granularity); + uptr unpoisoned_bytes = 0; + + uptr end = Max(granule_beg, dst_beg); + for (; dst_ptr != end; --dst_ptr, --src_ptr) + if (unpoisoned_bytes == 0 && !AddressIsPoisoned(src_ptr - 1)) + unpoisoned_bytes = dst_ptr - granule_beg; + + if (dst_ptr >= dst_end_down && !AddressIsPoisoned(dst_end)) + continue; + + if (granule_beg == dst_ptr || unpoisoned_bytes != 0) + SetContainerGranule(granule_beg, unpoisoned_bytes); + else if (!AddressIsPoisoned(dst_beg)) + SetContainerGranule(granule_beg, dst_beg - granule_beg); + } +} + +// A helper function for __sanitizer_copy_contiguous_container_annotations, +// has assumption about begin and end of the container. +// Should not be used stand alone. +static void CopyContainerFirstGranuleAnnotation(uptr src_beg, uptr dst_beg) { + constexpr uptr granularity = ASAN_SHADOW_GRANULARITY; + // First granule + uptr src_beg_down = RoundDownTo(src_beg, granularity); + uptr dst_beg_down = RoundDownTo(dst_beg, granularity); + if (dst_beg_down == dst_beg) + return; + if (!AddressIsPoisoned(src_beg)) + *(u8 *)MemToShadow(dst_beg_down) = *(u8 *)MemToShadow(src_beg_down); + else if (!AddressIsPoisoned(dst_beg)) + SetContainerGranule(dst_beg_down, dst_beg - dst_beg_down); +} + +// A helper function for __sanitizer_copy_contiguous_container_annotations, +// has assumption about begin and end of the container. +// Should not be used stand alone. +static void CopyContainerLastGranuleAnnotation(uptr src_end, uptr dst_end) { + constexpr uptr granularity = ASAN_SHADOW_GRANULARITY; + // Last granule + uptr src_end_down = RoundDownTo(src_end, granularity); + uptr dst_end_down = RoundDownTo(dst_end, granularity); + if (dst_end_down == dst_end || !AddressIsPoisoned(dst_end)) + return; + if (AddressIsPoisoned(src_end)) + *(u8 *)MemToShadow(dst_end_down) = *(u8 *)MemToShadow(src_end_down); + else + SetContainerGranule(dst_end_down, src_end - src_end_down); +} + +// This function copies ASan memory annotations (poisoned/unpoisoned states) +// from one buffer to another. +// It's main purpose is to help with relocating trivially relocatable objects, +// which memory may be poisoned, without calling copy constructor. +// However, it does not move memory content itself, only annotations. +// If the buffers aren't aligned (the distance between buffers isn't +// granule-aligned) +// // src_beg % granularity != dst_beg % granularity +// the function handles this by going byte by byte, slowing down performance. +// The old buffer annotations are not removed. If necessary, +// user can unpoison old buffer with __asan_unpoison_memory_region. +void __sanitizer_copy_contiguous_container_annotations(const void *src_beg_p, + const void *src_end_p, + const void *dst_beg_p, + const void *dst_end_p) { + if (!flags()->detect_container_overflow) + return; + + VPrintf(3, "contiguous_container_src: %p %p\n", src_beg_p, src_end_p); + VPrintf(3, "contiguous_container_dst: %p %p\n", dst_beg_p, dst_end_p); + + uptr src_beg = reinterpret_cast(src_beg_p); + uptr src_end = reinterpret_cast(src_end_p); + uptr dst_beg = reinterpret_cast(dst_beg_p); + uptr dst_end = reinterpret_cast(dst_end_p); + + constexpr uptr granularity = ASAN_SHADOW_GRANULARITY; + + if (src_beg > src_end || (dst_end - dst_beg) != (src_end - src_beg)) { + GET_STACK_TRACE_FATAL_HERE; + ReportBadParamsToCopyContiguousContainerAnnotations( + src_beg, src_end, dst_beg, dst_end, &stack); + } + + if (src_beg == src_end || src_beg == dst_beg) + return; + // Due to support for overlapping buffers, we may have to copy elements + // in reversed order, when destination buffer starts in the middle of + // the source buffer (or shares first granule with it). + // + // When buffers are not granule-aligned (or distance between them, + // to be specific), annotatios have to be copied byte by byte. + // + // The only remaining edge cases involve edge granules, + // when the container starts or ends within a granule. + uptr src_beg_up = RoundUpTo(src_beg, granularity); + uptr src_end_up = RoundUpTo(src_end, granularity); + bool copy_in_reversed_order = src_beg < dst_beg && dst_beg <= src_end_up; + if (src_beg % granularity != dst_beg % granularity || + RoundDownTo(dst_end - 1, granularity) <= dst_beg) { + if (copy_in_reversed_order) + SlowReversedCopyContainerAnnotations(src_beg, src_end, dst_beg, dst_end); + else + SlowCopyContainerAnnotations(src_beg, src_end, dst_beg, dst_end); + return; + } + + // As buffers are granule-aligned, we can just copy annotations of granules + // from the middle. + uptr dst_beg_up = RoundUpTo(dst_beg, granularity); + uptr dst_end_down = RoundDownTo(dst_end, granularity); + if (copy_in_reversed_order) + CopyContainerLastGranuleAnnotation(src_end, dst_end); + else + CopyContainerFirstGranuleAnnotation(src_beg, dst_beg); + + if (dst_beg_up < dst_end_down) { + internal_memmove((u8 *)MemToShadow(dst_beg_up), + (u8 *)MemToShadow(src_beg_up), + (dst_end_down - dst_beg_up) / granularity); + } + + if (copy_in_reversed_order) + CopyContainerFirstGranuleAnnotation(src_beg, dst_beg); + else + CopyContainerLastGranuleAnnotation(src_end, dst_end); +} + static const void *FindBadAddress(uptr begin, uptr end, bool poisoned) { CHECK_LE(begin, end); constexpr uptr kMaxRangeToCheck = 32; diff --git a/libsanitizer/asan/asan_posix.cpp b/libsanitizer/asan/asan_posix.cpp index e1f66641617c..39685696a0d0 100644 --- a/libsanitizer/asan/asan_posix.cpp +++ b/libsanitizer/asan/asan_posix.cpp @@ -59,10 +59,10 @@ bool PlatformUnpoisonStacks() { // Since we're on the signal alternate stack, we cannot find the DEFAULT // stack bottom using a local variable. - uptr default_bottom, tls_addr, tls_size, stack_size; - GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr, - &tls_size); - UnpoisonStack(default_bottom, default_bottom + stack_size, "default"); + uptr stack_begin, stack_end, tls_begin, tls_end; + GetThreadStackAndTls(/*main=*/false, &stack_begin, &stack_end, &tls_begin, + &tls_end); + UnpoisonStack(stack_begin, stack_end, "default"); return true; } @@ -146,7 +146,44 @@ void PlatformTSDDtor(void *tsd) { # endif AsanThread::TSDDtor(tsd); } -#endif +# endif + +static void BeforeFork() { + VReport(2, "BeforeFork tid: %llu\n", GetTid()); + if (CAN_SANITIZE_LEAKS) { + __lsan::LockGlobal(); + } + // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the + // stuff we need. + __lsan::LockThreads(); + __lsan::LockAllocator(); + StackDepotLockBeforeFork(); +} + +static void AfterFork(bool fork_child) { + StackDepotUnlockAfterFork(fork_child); + // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock + // the stuff we need. + __lsan::UnlockAllocator(); + __lsan::UnlockThreads(); + if (CAN_SANITIZE_LEAKS) { + __lsan::UnlockGlobal(); + } + VReport(2, "AfterFork tid: %llu\n", GetTid()); +} + +void InstallAtForkHandler() { +# if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE || \ + (SANITIZER_LINUX && SANITIZER_SPARC) + // While other Linux targets use clone in internal_fork which doesn't + // trigger pthread_atfork handlers, Linux/sparc64 uses __fork, causing a + // hang. + return; // FIXME: Implement FutexWait. +# endif + pthread_atfork( + &BeforeFork, []() { AfterFork(/* fork_child= */ false); }, + []() { AfterFork(/* fork_child= */ true); }); +} void InstallAtExitCheckLeaks() { if (CAN_SANITIZE_LEAKS) { diff --git a/libsanitizer/asan/asan_preinit.cpp b/libsanitizer/asan/asan_preinit.cpp index b07556ec96f8..23169383bb74 100644 --- a/libsanitizer/asan/asan_preinit.cpp +++ b/libsanitizer/asan/asan_preinit.cpp @@ -15,10 +15,8 @@ using namespace __asan; #if SANITIZER_CAN_USE_PREINIT_ARRAY - // The symbol is called __local_asan_preinit, because it's not intended to be - // exported. - // This code linked into the main executable when -fsanitize=address is in - // the link flags. It can only use exported interface functions. - __attribute__((section(".preinit_array"), used)) - void (*__local_asan_preinit)(void) = __asan_init; +// This section is linked into the main executable when -fsanitize=address is +// specified to perform initialization at a very early stage. +__attribute__((section(".preinit_array"), used)) static auto preinit = + __asan_init; #endif diff --git a/libsanitizer/asan/asan_premap_shadow.cpp b/libsanitizer/asan/asan_premap_shadow.cpp index bed2f62a2251..6e08b8f96650 100644 --- a/libsanitizer/asan/asan_premap_shadow.cpp +++ b/libsanitizer/asan/asan_premap_shadow.cpp @@ -33,7 +33,8 @@ uptr PremapShadowSize() { // PremapShadowSize() bytes on the right of it are mapped r/o. uptr PremapShadow() { return MapDynamicShadow(PremapShadowSize(), /*mmap_alignment_scale*/ 3, - /*min_shadow_base_alignment*/ 0, kHighMemEnd); + /*min_shadow_base_alignment*/ 0, kHighMemEnd, + GetMmapGranularity()); } bool PremapShadowFailed() { diff --git a/libsanitizer/asan/asan_report.cpp b/libsanitizer/asan/asan_report.cpp index 7603e8131154..45aa607dcda0 100644 --- a/libsanitizer/asan/asan_report.cpp +++ b/libsanitizer/asan/asan_report.cpp @@ -24,6 +24,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_interface_internal.h" +#include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_symbolizer.h" @@ -32,8 +33,11 @@ namespace __asan { // -------------------- User-specified callbacks ----------------- {{{1 static void (*error_report_callback)(const char*); -static char *error_message_buffer = nullptr; -static uptr error_message_buffer_pos = 0; +using ErrorMessageBuffer = InternalMmapVectorNoCtor; +alignas( + alignof(ErrorMessageBuffer)) static char error_message_buffer_placeholder + [sizeof(ErrorMessageBuffer)]; +static ErrorMessageBuffer *error_message_buffer = nullptr; static Mutex error_message_buf_mutex; static const unsigned kAsanBuggyPcPoolSize = 25; static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize]; @@ -42,17 +46,14 @@ void AppendToErrorMessageBuffer(const char *buffer) { Lock l(&error_message_buf_mutex); if (!error_message_buffer) { error_message_buffer = - (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__); - error_message_buffer_pos = 0; + new (error_message_buffer_placeholder) ErrorMessageBuffer(); + error_message_buffer->Initialize(kErrorMessageBufferSize); } - uptr length = internal_strlen(buffer); - RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos); - uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos; - internal_strncpy(error_message_buffer + error_message_buffer_pos, - buffer, remaining); - error_message_buffer[kErrorMessageBufferSize - 1] = '\0'; - // FIXME: reallocate the buffer instead of truncating the message. - error_message_buffer_pos += Min(remaining, length); + uptr error_message_buffer_len = error_message_buffer->size(); + uptr buffer_len = internal_strlen(buffer); + error_message_buffer->resize(error_message_buffer_len + buffer_len); + internal_memcpy(error_message_buffer->data() + error_message_buffer_len, + buffer, buffer_len); } // ---------------------- Helper functions ----------------------- {{{1 @@ -158,14 +159,14 @@ class ScopedInErrorReport { // Copy the message buffer so that we could start logging without holding a // lock that gets acquired during printing. - InternalMmapVector buffer_copy(kErrorMessageBufferSize); + InternalScopedString buffer_copy; { Lock l(&error_message_buf_mutex); - internal_memcpy(buffer_copy.data(), - error_message_buffer, kErrorMessageBufferSize); + error_message_buffer->push_back('\0'); + buffer_copy.Append(error_message_buffer->data()); // Clear error_message_buffer so that if we find other errors // we don't re-log this error. - error_message_buffer_pos = 0; + error_message_buffer->clear(); } LogFullErrorReport(buffer_copy.data()); @@ -366,6 +367,16 @@ void ReportBadParamsToAnnotateDoubleEndedContiguousContainer( in_report.ReportError(error); } +void ReportBadParamsToCopyContiguousContainerAnnotations( + uptr old_storage_beg, uptr old_storage_end, uptr new_storage_beg, + uptr new_storage_end, BufferedStackTrace *stack) { + ScopedInErrorReport in_report; + ErrorBadParamsToCopyContiguousContainerAnnotations error( + GetCurrentTidOrInvalid(), stack, old_storage_beg, old_storage_end, + new_storage_beg, new_storage_end); + in_report.ReportError(error); +} + void ReportODRViolation(const __asan_global *g1, u32 stack_id1, const __asan_global *g2, u32 stack_id2) { ScopedInErrorReport in_report; diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h index 3540b3b4b1bf..3143d83abe39 100644 --- a/libsanitizer/asan/asan_report.h +++ b/libsanitizer/asan/asan_report.h @@ -88,6 +88,9 @@ void ReportBadParamsToAnnotateDoubleEndedContiguousContainer( uptr storage_beg, uptr storage_end, uptr old_container_beg, uptr old_container_end, uptr new_container_beg, uptr new_container_end, BufferedStackTrace *stack); +void ReportBadParamsToCopyContiguousContainerAnnotations( + uptr old_storage_beg, uptr old_storage_end, uptr new_storage_beg, + uptr new_storage_end, BufferedStackTrace *stack); void ReportODRViolation(const __asan_global *g1, u32 stack_id1, const __asan_global *g2, u32 stack_id2); diff --git a/libsanitizer/asan/asan_rtl.cpp b/libsanitizer/asan/asan_rtl.cpp index d1e7856973b4..19c6c210b564 100644 --- a/libsanitizer/asan/asan_rtl.cpp +++ b/libsanitizer/asan/asan_rtl.cpp @@ -71,16 +71,16 @@ static void CheckUnwind() { } // -------------------------- Globals --------------------- {{{1 -static int asan_inited = 0; -static int asan_init_is_running = 0; +static StaticSpinMutex asan_inited_mutex; +static atomic_uint8_t asan_inited = {0}; -void SetAsanInited(u32 val) { asan_inited = val; } - -void SetAsanInitIsRunning(u32 val) { asan_init_is_running = val; } - -bool AsanInited() { return asan_inited == 1; } +static void SetAsanInited() { + atomic_store(&asan_inited, 1, memory_order_release); +} -bool AsanInitIsRunning() { return asan_init_is_running == 1; } +bool AsanInited() { + return atomic_load(&asan_inited, memory_order_acquire) == 1; +} bool replace_intrin_cached; @@ -382,7 +382,7 @@ void PrintAddressSpaceLayout() { Printf("SHADOW_SCALE: %d\n", (int)ASAN_SHADOW_SCALE); Printf("SHADOW_GRANULARITY: %d\n", (int)ASAN_SHADOW_GRANULARITY); - Printf("SHADOW_OFFSET: 0x%zx\n", (uptr)ASAN_SHADOW_OFFSET); + Printf("SHADOW_OFFSET: %p\n", (void *)ASAN_SHADOW_OFFSET); CHECK(ASAN_SHADOW_SCALE >= 3 && ASAN_SHADOW_SCALE <= 7); if (kMidMemBeg) CHECK(kMidShadowBeg > kLowShadowEnd && @@ -390,12 +390,10 @@ void PrintAddressSpaceLayout() { kHighShadowBeg > kMidMemEnd); } -static void AsanInitInternal() { +static bool AsanInitInternal() { if (LIKELY(AsanInited())) - return; + return true; SanitizerToolName = "AddressSanitizer"; - CHECK(!AsanInitIsRunning() && "ASan init calls itself!"); - SetAsanInitIsRunning(1); CacheBinaryName(); @@ -408,11 +406,12 @@ static void AsanInitInternal() { // 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())) { - SetAsanInitIsRunning(0); VReport(1, "AddressSanitizer init is being performed for dlopen().\n"); - return; + return false; } + // Make sure we are not statically linked. + __interception::DoesNotSupportStaticLinking(); AsanCheckIncompatibleRT(); AsanCheckDynamicRTPrereqs(); AvoidCVE_2016_2143(); @@ -424,9 +423,6 @@ static void AsanInitInternal() { InitializeHighMemEnd(); - // Make sure we are not statically linked. - AsanDoesNotSupportStaticLinkage(); - // Install tool-specific callbacks in sanitizer_common. AddDieCallback(AsanDie); SetCheckUnwindCallback(CheckUnwind); @@ -470,8 +466,7 @@ static void AsanInitInternal() { // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited // should be set to 1 prior to initializing the threads. replace_intrin_cached = flags()->replace_intrin; - SetAsanInited(1); - SetAsanInitIsRunning(0); + SetAsanInited(); if (flags()->atexit) Atexit(asan_atexit); @@ -483,9 +478,6 @@ static void AsanInitInternal() { if (flags()->start_deactivated) AsanDeactivate(); - // interceptors - InitTlsSize(); - // Create main thread. AsanThread *main_thread = CreateMainThread(); CHECK_EQ(0, main_thread->tid()); @@ -497,6 +489,8 @@ static void AsanInitInternal() { InstallAtExitCheckLeaks(); } + InstallAtForkHandler(); + #if CAN_SANITIZE_UB __ubsan::InitAsPlugin(); #endif @@ -515,14 +509,29 @@ static void AsanInitInternal() { VReport(1, "AddressSanitizer Init done\n"); WaitForDebugger(flags()->sleep_after_init, "after init"); + + return true; } // Initialize as requested from some part of ASan runtime library (interceptors, // allocator, etc). void AsanInitFromRtl() { + if (LIKELY(AsanInited())) + return; + SpinMutexLock lock(&asan_inited_mutex); AsanInitInternal(); } +bool TryAsanInitFromRtl() { + if (LIKELY(AsanInited())) + return true; + if (!asan_inited_mutex.TryLock()) + return false; + bool result = AsanInitInternal(); + asan_inited_mutex.Unlock(); + return result; +} + #if ASAN_DYNAMIC // Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable // (and thus normal initializers from .preinit_array or modules haven't run). @@ -568,10 +577,8 @@ static void UnpoisonDefaultStack() { } else { CHECK(!SANITIZER_FUCHSIA); // If we haven't seen this thread, try asking the OS for stack bounds. - uptr tls_addr, tls_size, stack_size; - GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr, - &tls_size); - top = bottom + stack_size; + uptr tls_begin, tls_end; + GetThreadStackAndTls(/*main=*/false, &bottom, &top, &tls_begin, &tls_end); } UnpoisonStack(bottom, top, "default"); @@ -593,7 +600,7 @@ static void UnpoisonFakeStack() { using namespace __asan; void NOINLINE __asan_handle_no_return() { - if (AsanInitIsRunning()) + if (UNLIKELY(!AsanInited())) return; if (!PlatformUnpoisonStacks()) @@ -623,7 +630,7 @@ void NOINLINE __asan_set_death_callback(void (*callback)(void)) { // We use this call as a trigger to wake up ASan from deactivated state. void __asan_init() { AsanActivate(); - AsanInitInternal(); + AsanInitFromRtl(); } void __asan_version_mismatch_check() { diff --git a/libsanitizer/asan/asan_rtl_x86_64.S b/libsanitizer/asan/asan_rtl_x86_64.S index 0b7363018f42..9c5289856d8a 100644 --- a/libsanitizer/asan/asan_rtl_x86_64.S +++ b/libsanitizer/asan/asan_rtl_x86_64.S @@ -27,7 +27,12 @@ FNAME(reg, op, s, i): ;\ #define ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, s) \ mov %##reg,%r10 ;\ shr $0x3,%r10 ;\ + .if ASAN_SHADOW_OFFSET_CONST < 0x80000000 ;\ movsbl ASAN_SHADOW_OFFSET_CONST(%r10),%r10d ;\ + .else ;\ + movabsq $ASAN_SHADOW_OFFSET_CONST,%r11 ;\ + movsbl (%r10,%r11),%r10d ;\ + .endif ;\ test %r10d,%r10d ;\ jne CLABEL(reg, op, s, add) ;\ RLABEL(reg, op, s, add): ;\ @@ -84,7 +89,12 @@ ENDF #define ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, s, c) \ mov %##reg,%r10 ;\ shr $0x3,%r10 ;\ + .if ASAN_SHADOW_OFFSET_CONST < 0x80000000 ;\ ##c $0x0,ASAN_SHADOW_OFFSET_CONST(%r10) ;\ + .else ;\ + movabsq $ASAN_SHADOW_OFFSET_CONST,%r11 ;\ + ##c $0x0,(%r10,%r11) ;\ + .endif ;\ jne FLABEL(reg, op, s, add) ;\ retq ;\ diff --git a/libsanitizer/asan/asan_suppressions.cpp b/libsanitizer/asan/asan_suppressions.cpp index 8cb2c3e3b9b6..94289d14d7e7 100644 --- a/libsanitizer/asan/asan_suppressions.cpp +++ b/libsanitizer/asan/asan_suppressions.cpp @@ -20,7 +20,7 @@ namespace __asan { -ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; +alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)]; static SuppressionContext *suppression_ctx = nullptr; static const char kInterceptorName[] = "interceptor_name"; static const char kInterceptorViaFunction[] = "interceptor_via_fun"; @@ -39,8 +39,7 @@ void InitializeSuppressions() { suppression_ctx = new (suppression_placeholder) SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); - if (&__asan_default_suppressions) - suppression_ctx->Parse(__asan_default_suppressions()); + suppression_ctx->Parse(__asan_default_suppressions()); } bool IsInterceptorSuppressed(const char *interceptor_name) { @@ -81,9 +80,10 @@ bool IsStackTraceSuppressed(const StackTrace *stack) { } if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) { - SymbolizedStack *frames = symbolizer->SymbolizePC(addr); + SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr)); + const SymbolizedStack *frames = symbolized_stack.get(); CHECK(frames); - for (SymbolizedStack *cur = frames; cur; cur = cur->next) { + for (const SymbolizedStack *cur = frames; cur; cur = cur->next) { const char *function_name = cur->info.function; if (!function_name) { continue; @@ -91,11 +91,9 @@ bool IsStackTraceSuppressed(const StackTrace *stack) { // Match "interceptor_via_fun" suppressions. if (suppression_ctx->Match(function_name, kInterceptorViaFunction, &s)) { - frames->ClearAll(); return true; } } - frames->ClearAll(); } } return false; diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp index 8798968947e8..37fb6f2b07f2 100644 --- a/libsanitizer/asan/asan_thread.cpp +++ b/libsanitizer/asan/asan_thread.cpp @@ -21,6 +21,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stackdepot.h" +#include "sanitizer_common/sanitizer_thread_history.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" namespace __asan { @@ -28,10 +29,7 @@ namespace __asan { // AsanThreadContext implementation. void AsanThreadContext::OnCreated(void *arg) { - CreateThreadContextArgs *args = static_cast(arg); - if (args->stack) - stack_id = StackDepotPut(*args->stack); - thread = args->thread; + thread = static_cast(arg); thread->set_context(this); } @@ -44,10 +42,15 @@ static ThreadRegistry *asan_thread_registry; static ThreadArgRetval *thread_data; static Mutex mu_for_thread_context; +// TODO(leonardchan@): It should be possible to make LowLevelAllocator +// threadsafe and consolidate this one into the GlobalLoweLevelAllocator. +// We should be able to do something similar to what's in +// sanitizer_stack_store.cpp. +static LowLevelAllocator allocator_for_thread_context; static ThreadContextBase *GetAsanThreadContext(u32 tid) { Lock lock(&mu_for_thread_context); - return new (GetGlobalLowLevelAllocator()) AsanThreadContext(tid); + return new (allocator_for_thread_context) AsanThreadContext(tid); } static void InitThreads() { @@ -62,10 +65,10 @@ static void InitThreads() { // thread before all TSD destructors will be called for it. // MIPS requires aligned address - static ALIGNED(alignof( - ThreadRegistry)) char thread_registry_placeholder[sizeof(ThreadRegistry)]; - static ALIGNED(alignof( - ThreadArgRetval)) char thread_data_placeholder[sizeof(ThreadArgRetval)]; + alignas(alignof(ThreadRegistry)) static char + thread_registry_placeholder[sizeof(ThreadRegistry)]; + alignas(alignof(ThreadArgRetval)) static char + thread_data_placeholder[sizeof(ThreadArgRetval)]; asan_thread_registry = new (thread_registry_placeholder) ThreadRegistry(GetAsanThreadContext); @@ -101,8 +104,8 @@ AsanThread *AsanThread::Create(const void *start_data, uptr data_size, CHECK_LE(data_size, availible_size); internal_memcpy(thread->start_data_, start_data, data_size); } - AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; - asanThreadRegistry().CreateThread(0, detached, parent_tid, &args); + asanThreadRegistry().CreateThread(0, detached, parent_tid, + stack ? StackDepotPut(*stack) : 0, thread); return thread; } @@ -301,13 +304,10 @@ AsanThread *CreateMainThread() { // OS-specific implementations that need more information passed through. void AsanThread::SetThreadStackAndTls(const InitOptions *options) { DCHECK_EQ(options, nullptr); - uptr tls_size = 0; - uptr stack_size = 0; - GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size, - &tls_begin_, &tls_size); - stack_top_ = RoundDownTo(stack_bottom_ + stack_size, ASAN_SHADOW_GRANULARITY); + GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_top_, + &tls_begin_, &tls_end_); + stack_top_ = RoundDownTo(stack_top_, ASAN_SHADOW_GRANULARITY); stack_bottom_ = RoundDownTo(stack_bottom_, ASAN_SHADOW_GRANULARITY); - tls_end_ = tls_begin_ + tls_size; dtls_ = DTLS_Get(); if (stack_top_ != stack_bottom_) { @@ -556,6 +556,12 @@ void GetRunningThreadsLocked(InternalMmapVector *threads) { threads); } +void PrintThreads() { + InternalScopedString out; + PrintThreadHistory(__asan::asanThreadRegistry(), out); + Report("%s\n", out.data()); +} + } // namespace __lsan // ---------------------- Interface ---------------- {{{1 diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h index 62f1b5337fe4..ad9e03d68fe9 100644 --- a/libsanitizer/asan/asan_thread.h +++ b/libsanitizer/asan/asan_thread.h @@ -36,21 +36,16 @@ class AsanThread; class AsanThreadContext final : public ThreadContextBase { public: explicit AsanThreadContext(int tid) - : ThreadContextBase(tid), announced(false), - destructor_iterations(GetPthreadDestructorIterations()), stack_id(0), + : ThreadContextBase(tid), + announced(false), + destructor_iterations(GetPthreadDestructorIterations()), thread(nullptr) {} bool announced; u8 destructor_iterations; - u32 stack_id; AsanThread *thread; void OnCreated(void *arg) override; void OnFinished() override; - - struct CreateThreadContextArgs { - AsanThread *thread; - StackTrace *stack; - }; }; // AsanThreadContext objects are never freed, so we need many of them. diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp index d5a30f471e2b..09a13b11cff1 100644 --- a/libsanitizer/asan/asan_win.cpp +++ b/libsanitizer/asan/asan_win.cpp @@ -203,6 +203,8 @@ void InitializePlatformInterceptors() { void InstallAtExitCheckLeaks() {} +void InstallAtForkHandler() {} + void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { UNIMPLEMENTED(); } @@ -264,16 +266,10 @@ void PlatformTSDDtor(void *tsd) { AsanThread::TSDDtor(tsd); } // }}} // ---------------------- Various stuff ---------------- {{{ -void *AsanDoesNotSupportStaticLinkage() { -#if defined(_DEBUG) -#error Please build the runtime with a non-debug CRT: /MD or /MT -#endif - return 0; -} - uptr FindDynamicShadowStart() { return MapDynamicShadow(MemToShadowSize(kHighMemEnd), ASAN_SHADOW_SCALE, - /*min_shadow_base_alignment*/ 0, kHighMemEnd); + /*min_shadow_base_alignment*/ 0, kHighMemEnd, + GetMmapGranularity()); } void AsanCheckDynamicRTPrereqs() {} diff --git a/libsanitizer/asan/asan_win_common_runtime_thunk.cpp b/libsanitizer/asan/asan_win_common_runtime_thunk.cpp new file mode 100644 index 000000000000..056e49336d32 --- /dev/null +++ b/libsanitizer/asan/asan_win_common_runtime_thunk.cpp @@ -0,0 +1,112 @@ +//===-- asan_win_common_runtime_thunk.cpp --------------------------- -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This file defines things that need to be present in the application modules +// to interact with the ASan DLL runtime correctly and can't be implemented +// using the default "import library" generated when linking the DLL. +// +// This includes: +// - Cloning shadow memory dynamic address from ASAN DLL +// - Creating weak aliases to default implementation imported from asan dll +// - Forwarding the detect_stack_use_after_return runtime option +// - installing a custom SEH handler +// +//===----------------------------------------------------------------------===// + +#if defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || \ + defined(SANITIZER_STATIC_RUNTIME_THUNK) +# define SANITIZER_IMPORT_INTERFACE 1 +# define WIN32_LEAN_AND_MEAN +# include "asan_win_common_runtime_thunk.h" + +# include + +# include "sanitizer_common/sanitizer_win_defs.h" +# include "sanitizer_common/sanitizer_win_thunk_interception.h" + +// Define weak alias for all weak functions imported from asan dll. +# define INTERFACE_FUNCTION(Name) +# define INTERFACE_WEAK_FUNCTION(Name) REGISTER_WEAK_FUNCTION(Name) +# include "asan_interface.inc" + +//////////////////////////////////////////////////////////////////////////////// +// Define a copy of __asan_option_detect_stack_use_after_return that should be +// used when linking an MD runtime with a set of object files on Windows. +// +// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return', +// so normally we would just dllimport it. Unfortunately, the dllimport +// attribute adds __imp_ prefix to the symbol name of a variable. +// Since in general we don't know if a given TU is going to be used +// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows +// just to work around this issue, let's clone the variable that is constant +// after initialization anyways. + +extern "C" { +__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); +int __asan_option_detect_stack_use_after_return; + +__declspec(dllimport) void *__asan_get_shadow_memory_dynamic_address(); +void *__asan_shadow_memory_dynamic_address; + +static void __asan_initialize_cloned_variables() { + __asan_option_detect_stack_use_after_return = + __asan_should_detect_stack_use_after_return(); + __asan_shadow_memory_dynamic_address = + __asan_get_shadow_memory_dynamic_address(); +} +} + +static int asan_thunk_init() { + __asan_initialize_cloned_variables(); + +# ifdef SANITIZER_STATIC_RUNTIME_THUNK + __asan_initialize_static_thunk(); +# endif + + return 0; +} + +static void WINAPI asan_thread_init(void *mod, unsigned long reason, + void *reserved) { + if (reason == DLL_PROCESS_ATTACH) { + asan_thunk_init(); + } +} + +// Our cloned variables must be initialized before C/C++ constructors. If TLS +// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB +// initializer is needed as a backup. +extern "C" __declspec(allocate(".CRT$XIB")) int (*__asan_thunk_init)() = + asan_thunk_init; +WIN_FORCE_LINK(__asan_thunk_init) + +extern "C" __declspec(allocate(".CRT$XLAB")) void(WINAPI *__asan_tls_init)( + void *, unsigned long, void *) = asan_thread_init; +WIN_FORCE_LINK(__asan_tls_init) + +//////////////////////////////////////////////////////////////////////////////// +// ASan SEH handling. +// We need to set the ASan-specific SEH handler at the end of CRT initialization +// of each module (see also asan_win.cpp). +extern "C" { +__declspec(dllimport) int __asan_set_seh_filter(); +static int SetSEHFilter() { return __asan_set_seh_filter(); } + +// Unfortunately, putting a pointer to __asan_set_seh_filter into +// __asan_intercept_seh gets optimized out, so we have to use an extra function. +extern "C" __declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() = + SetSEHFilter; +WIN_FORCE_LINK(__asan_seh_interceptor) +} + +WIN_FORCE_LINK(__asan_dso_reg_hook) + +#endif // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || + // defined(SANITIZER_STATIC_RUNTIME_THUNK) diff --git a/libsanitizer/asan/asan_win_common_runtime_thunk.h b/libsanitizer/asan/asan_win_common_runtime_thunk.h new file mode 100644 index 000000000000..159cc152474e --- /dev/null +++ b/libsanitizer/asan/asan_win_common_runtime_thunk.h @@ -0,0 +1,38 @@ +//===-- asan_win_common_runtime_thunk.h -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This file defines things that need to be present in the application modules +// to interact with the ASan DLL runtime correctly and can't be implemented +// using the default "import library" generated when linking the DLL. +// +//===----------------------------------------------------------------------===// + +#if defined(SANITIZER_STATIC_RUNTIME_THUNK) || \ + defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) +# include "sanitizer_common/sanitizer_win_defs.h" + +# pragma section(".CRT$XIB", long, \ + read) // C initializer (during C init before dyninit) +# pragma section(".CRT$XID", long, \ + read) // First C initializer after CRT initializers +# pragma section(".CRT$XCAB", long, \ + read) // First C++ initializer after startup initializers + +# pragma section(".CRT$XTW", long, read) // First ASAN globals terminator +# pragma section(".CRT$XTY", long, read) // Last ASAN globals terminator + +# pragma section(".CRT$XLAB", long, read) // First TLS initializer + +# ifdef SANITIZER_STATIC_RUNTIME_THUNK +extern "C" void __asan_initialize_static_thunk(); +# endif + +#endif // defined(SANITIZER_STATIC_RUNTIME_THUNK) || + // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) \ No newline at end of file diff --git a/libsanitizer/asan/asan_win_dll_thunk.cpp b/libsanitizer/asan/asan_win_dll_thunk.cpp deleted file mode 100644 index 0fa636bec0d0..000000000000 --- a/libsanitizer/asan/asan_win_dll_thunk.cpp +++ /dev/null @@ -1,165 +0,0 @@ -//===-- asan_win_dll_thunk.cpp --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of AddressSanitizer, an address sanity checker. -// -// This file defines a family of thunks that should be statically linked into -// the DLLs that have ASan instrumentation in order to delegate the calls to the -// shared runtime that lives in the main binary. -// See https://github.com/google/sanitizers/issues/209 for the details. -//===----------------------------------------------------------------------===// - -#ifdef SANITIZER_DLL_THUNK -#include "asan_init_version.h" -#include "interception/interception.h" -#include "sanitizer_common/sanitizer_win_defs.h" -#include "sanitizer_common/sanitizer_win_dll_thunk.h" -#include "sanitizer_common/sanitizer_platform_interceptors.h" - -// ASan own interface functions. -#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "asan_interface.inc" - -// Memory allocation functions. -INTERCEPT_WRAP_V_W(free) -INTERCEPT_WRAP_V_W(_free_base) -INTERCEPT_WRAP_V_WW(_free_dbg) - -INTERCEPT_WRAP_W_W(malloc) -INTERCEPT_WRAP_W_W(_malloc_base) -INTERCEPT_WRAP_W_WWWW(_malloc_dbg) - -INTERCEPT_WRAP_W_WW(calloc) -INTERCEPT_WRAP_W_WW(_calloc_base) -INTERCEPT_WRAP_W_WWWWW(_calloc_dbg) -INTERCEPT_WRAP_W_WWW(_calloc_impl) - -INTERCEPT_WRAP_W_WW(realloc) -INTERCEPT_WRAP_W_WW(_realloc_base) -INTERCEPT_WRAP_W_WWW(_realloc_dbg) -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) - -// TODO(timurrrr): Might want to add support for _aligned_* allocation -// functions to detect a bit more bugs. Those functions seem to wrap malloc(). - -// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cpp) - -# if defined(_MSC_VER) && !defined(__clang__) -// Disable warnings such as: 'void memchr(void)': incorrect number of arguments -// for intrinsic function, expected '3' arguments. -# pragma warning(push) -# pragma warning(disable : 4392) -# endif - -INTERCEPT_LIBRARY_FUNCTION(atoi); -INTERCEPT_LIBRARY_FUNCTION(atol); -INTERCEPT_LIBRARY_FUNCTION(atoll); -INTERCEPT_LIBRARY_FUNCTION(frexp); -INTERCEPT_LIBRARY_FUNCTION(longjmp); -#if SANITIZER_INTERCEPT_MEMCHR -INTERCEPT_LIBRARY_FUNCTION(memchr); -#endif -INTERCEPT_LIBRARY_FUNCTION(memcmp); -INTERCEPT_LIBRARY_FUNCTION(memcpy); -INTERCEPT_LIBRARY_FUNCTION(memmove); -INTERCEPT_LIBRARY_FUNCTION(memset); -INTERCEPT_LIBRARY_FUNCTION(strcat); -INTERCEPT_LIBRARY_FUNCTION(strchr); -INTERCEPT_LIBRARY_FUNCTION(strcmp); -INTERCEPT_LIBRARY_FUNCTION(strcpy); -INTERCEPT_LIBRARY_FUNCTION(strcspn); -INTERCEPT_LIBRARY_FUNCTION(strdup); -INTERCEPT_LIBRARY_FUNCTION(strlen); -INTERCEPT_LIBRARY_FUNCTION(strncat); -INTERCEPT_LIBRARY_FUNCTION(strncmp); -INTERCEPT_LIBRARY_FUNCTION(strncpy); -INTERCEPT_LIBRARY_FUNCTION(strnlen); -INTERCEPT_LIBRARY_FUNCTION(strpbrk); -INTERCEPT_LIBRARY_FUNCTION(strrchr); -INTERCEPT_LIBRARY_FUNCTION(strspn); -INTERCEPT_LIBRARY_FUNCTION(strstr); -INTERCEPT_LIBRARY_FUNCTION(strtok); -INTERCEPT_LIBRARY_FUNCTION(strtol); -INTERCEPT_LIBRARY_FUNCTION(strtoll); -INTERCEPT_LIBRARY_FUNCTION(wcslen); -INTERCEPT_LIBRARY_FUNCTION(wcsnlen); - -# if defined(_MSC_VER) && !defined(__clang__) -# pragma warning(pop) -# endif - -#ifdef _WIN64 -INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler); -#else -INTERCEPT_LIBRARY_FUNCTION(_except_handler3); -// _except_handler4 checks -GS cookie which is different for each module, so we -// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4). -INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { - __asan_handle_no_return(); - return REAL(_except_handler4)(a, b, c, d); -} -#endif - -// Windows specific functions not included in asan_interface.inc. -INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return) -INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address) -INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter) - -using namespace __sanitizer; - -extern "C" { -int __asan_option_detect_stack_use_after_return; -uptr __asan_shadow_memory_dynamic_address; -} // extern "C" - -static int asan_dll_thunk_init() { - typedef void (*fntype)(); - static fntype fn = 0; - // asan_dll_thunk_init is expected to be called by only one thread. - if (fn) return 0; - - // Ensure all interception was executed. - __dll_thunk_init(); - - fn = (fntype) dllThunkGetRealAddrOrDie("__asan_init"); - fn(); - __asan_option_detect_stack_use_after_return = - (__asan_should_detect_stack_use_after_return() != 0); - __asan_shadow_memory_dynamic_address = - (uptr)__asan_get_shadow_memory_dynamic_address(); - -#ifndef _WIN64 - INTERCEPT_FUNCTION(_except_handler4); -#endif - // In DLLs, the callbacks are expected to return 0, - // otherwise CRT initialization fails. - return 0; -} - -#pragma section(".CRT$XIB", long, read) -__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = asan_dll_thunk_init; - -static void WINAPI asan_thread_init(void *mod, unsigned long reason, - void *reserved) { - if (reason == /*DLL_PROCESS_ATTACH=*/1) asan_dll_thunk_init(); -} - -#pragma section(".CRT$XLAB", long, read) -__declspec(allocate(".CRT$XLAB")) void (WINAPI *__asan_tls_init)(void *, - unsigned long, void *) = asan_thread_init; - -WIN_FORCE_LINK(__asan_dso_reg_hook) - -#endif // SANITIZER_DLL_THUNK diff --git a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp index f0b5ec9eef7f..421fe651b7d9 100644 --- a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp +++ b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp @@ -8,76 +8,17 @@ // // This file is a part of AddressSanitizer, an address sanity checker. // -// This file defines things that need to be present in the application modules -// to interact with the ASan DLL runtime correctly and can't be implemented -// using the default "import library" generated when linking the DLL RTL. -// -// This includes: -// - creating weak aliases to default implementation imported from asan dll. -// - forwarding the detect_stack_use_after_return runtime option -// - working around deficiencies of the MD runtime -// - installing a custom SEH handler +// This file defines things that need to be present for application modules +// that are dynamic linked with the C Runtime. // //===----------------------------------------------------------------------===// #ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK -#define SANITIZER_IMPORT_INTERFACE 1 -#include "sanitizer_common/sanitizer_win_defs.h" -#define WIN32_LEAN_AND_MEAN -#include - -// Define weak alias for all weak functions imported from asan dll. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name) -#include "asan_interface.inc" - -// First, declare CRT sections we'll be using in this file -#pragma section(".CRT$XIB", long, read) -#pragma section(".CRT$XID", long, read) -#pragma section(".CRT$XCAB", long, read) -#pragma section(".CRT$XTW", long, read) -#pragma section(".CRT$XTY", long, read) -#pragma section(".CRT$XLAB", long, read) - -//////////////////////////////////////////////////////////////////////////////// -// Define a copy of __asan_option_detect_stack_use_after_return that should be -// used when linking an MD runtime with a set of object files on Windows. -// -// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return', -// so normally we would just dllimport it. Unfortunately, the dllimport -// attribute adds __imp_ prefix to the symbol name of a variable. -// Since in general we don't know if a given TU is going to be used -// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows -// just to work around this issue, let's clone the variable that is constant -// after initialization anyways. -extern "C" { -__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); -int __asan_option_detect_stack_use_after_return; - -__declspec(dllimport) void* __asan_get_shadow_memory_dynamic_address(); -void* __asan_shadow_memory_dynamic_address; -} - -static int InitializeClonedVariables() { - __asan_option_detect_stack_use_after_return = - __asan_should_detect_stack_use_after_return(); - __asan_shadow_memory_dynamic_address = - __asan_get_shadow_memory_dynamic_address(); - return 0; -} - -static void NTAPI asan_thread_init(void *mod, unsigned long reason, - void *reserved) { - if (reason == DLL_PROCESS_ATTACH) InitializeClonedVariables(); -} +# define WIN32_LEAN_AND_MEAN +# include -// Our cloned variables must be initialized before C/C++ constructors. If TLS -// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB -// initializer is needed as a backup. -__declspec(allocate(".CRT$XIB")) int (*__asan_initialize_cloned_variables)() = - InitializeClonedVariables; -__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *, - unsigned long, void *) = asan_thread_init; +# include "asan_win_common_runtime_thunk.h" +# include "sanitizer_common/sanitizer_win_defs.h" //////////////////////////////////////////////////////////////////////////////// // For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL @@ -88,43 +29,26 @@ __declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *, // using atexit() that calls a small subset of C terminators // where LLVM global_dtors is placed. Fingers crossed, no other C terminators // are there. -extern "C" int __cdecl atexit(void (__cdecl *f)(void)); +extern "C" int __cdecl atexit(void(__cdecl *f)(void)); extern "C" void __cdecl _initterm(void *a, void *b); namespace { -__declspec(allocate(".CRT$XTW")) void* before_global_dtors = 0; -__declspec(allocate(".CRT$XTY")) void* after_global_dtors = 0; +__declspec(allocate(".CRT$XTW")) void *before_global_dtors = 0; +__declspec(allocate(".CRT$XTY")) void *after_global_dtors = 0; void UnregisterGlobals() { _initterm(&before_global_dtors, &after_global_dtors); } -int ScheduleUnregisterGlobals() { - return atexit(UnregisterGlobals); -} +int ScheduleUnregisterGlobals() { return atexit(UnregisterGlobals); } } // namespace // We need to call 'atexit(UnregisterGlobals);' as early as possible, but after // atexit() is initialized (.CRT$XIC). As this is executed before C++ // initializers (think ctors for globals), UnregisterGlobals gets executed after // dtors for C++ globals. -__declspec(allocate(".CRT$XID")) -int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; - -//////////////////////////////////////////////////////////////////////////////// -// ASan SEH handling. -// We need to set the ASan-specific SEH handler at the end of CRT initialization -// of each module (see also asan_win.cpp). -extern "C" { -__declspec(dllimport) int __asan_set_seh_filter(); -static int SetSEHFilter() { return __asan_set_seh_filter(); } - -// Unfortunately, putting a pointer to __asan_set_seh_filter into -// __asan_intercept_seh gets optimized out, so we have to use an extra function. -__declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() = - SetSEHFilter; -} - -WIN_FORCE_LINK(__asan_dso_reg_hook) +extern "C" __declspec(allocate(".CRT$XID")) int ( + *__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; +WIN_FORCE_LINK(__asan_schedule_unregister_globals) -#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK +#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK diff --git a/libsanitizer/asan/asan_win_static_runtime_thunk.cpp b/libsanitizer/asan/asan_win_static_runtime_thunk.cpp new file mode 100644 index 000000000000..4a69b6657403 --- /dev/null +++ b/libsanitizer/asan/asan_win_static_runtime_thunk.cpp @@ -0,0 +1,113 @@ +//===-- asan_win_static_runtime_thunk.cpp ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This file defines a family of thunks that should be statically linked into +// modules that are statically linked with the C Runtime in order to delegate +// the calls to the ASAN runtime DLL. +// See https://github.com/google/sanitizers/issues/209 for the details. +//===----------------------------------------------------------------------===// + +#ifdef SANITIZER_STATIC_RUNTIME_THUNK +# include "asan_init_version.h" +# include "asan_interface_internal.h" +# include "asan_win_common_runtime_thunk.h" +# include "sanitizer_common/sanitizer_platform_interceptors.h" +# include "sanitizer_common/sanitizer_win_defs.h" +# include "sanitizer_common/sanitizer_win_thunk_interception.h" + +# if defined(_MSC_VER) && !defined(__clang__) +// Disable warnings such as: 'void memchr(void)': incorrect number of arguments +// for intrinsic function, expected '3' arguments. +# pragma warning(push) +# pragma warning(disable : 4392) +# endif + +# define INTERCEPT_LIBRARY_FUNCTION_ASAN(X) \ + INTERCEPT_LIBRARY_FUNCTION(X, "__asan_wrap_" #X) + +INTERCEPT_LIBRARY_FUNCTION_ASAN(atoi); +INTERCEPT_LIBRARY_FUNCTION_ASAN(atol); +INTERCEPT_LIBRARY_FUNCTION_ASAN(atoll); +INTERCEPT_LIBRARY_FUNCTION_ASAN(frexp); +INTERCEPT_LIBRARY_FUNCTION_ASAN(longjmp); +# if SANITIZER_INTERCEPT_MEMCHR +INTERCEPT_LIBRARY_FUNCTION_ASAN(memchr); +# endif +INTERCEPT_LIBRARY_FUNCTION_ASAN(memcmp); +INTERCEPT_LIBRARY_FUNCTION_ASAN(memcpy); +# ifndef _WIN64 +// memmove and memcpy share an implementation on amd64 +INTERCEPT_LIBRARY_FUNCTION_ASAN(memmove); +# endif +INTERCEPT_LIBRARY_FUNCTION_ASAN(memset); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strcat); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strchr); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strcmp); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strcpy); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strcspn); +INTERCEPT_LIBRARY_FUNCTION_ASAN(_strdup); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strlen); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strncat); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strncmp); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strncpy); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strnlen); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strpbrk); +// INTERCEPT_LIBRARY_FUNCTION_ASAN(strrchr); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strspn); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strstr); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strtok); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcslen); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsnlen); + +// Note: Don't intercept strtol(l). They are supposed to set errno for out-of- +// range values, but since the ASan runtime is linked against the dynamic CRT, +// its errno is different from the one in the current module. + +# if defined(_MSC_VER) && !defined(__clang__) +# pragma warning(pop) +# endif + +# ifdef _WIN64 +INTERCEPT_LIBRARY_FUNCTION_ASAN(__C_specific_handler); +# else +extern "C" void abort(); +INTERCEPT_LIBRARY_FUNCTION_ASAN(_except_handler3); +// _except_handler4 checks -GS cookie which is different for each module, so we +// can't use INTERCEPT_LIBRARY_FUNCTION_ASAN(_except_handler4), need to apply +// manually +extern "C" int _except_handler4(void *, void *, void *, void *); +static int (*real_except_handler4)(void *, void *, void *, + void *) = &_except_handler4; +static int intercept_except_handler4(void *a, void *b, void *c, void *d) { + __asan_handle_no_return(); + return real_except_handler4(a, b, c, d); +} +# endif + +// Windows specific functions not included in asan_interface.inc. +// INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return) +// INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address) +// INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter) + +extern "C" void __asan_initialize_static_thunk() { +# ifndef _WIN64 + if (real_except_handler4 == &_except_handler4) { + // Single threaded, no need for synchronization. + if (!__sanitizer_override_function_by_addr( + reinterpret_cast<__sanitizer::uptr>(&intercept_except_handler4), + reinterpret_cast<__sanitizer::uptr>(&_except_handler4), + reinterpret_cast<__sanitizer::uptr*>(&real_except_handler4))) { + abort(); + } + } +# endif +} + +#endif // SANITIZER_DLL_THUNK diff --git a/libsanitizer/asan/asan_win_weak_interception.cpp b/libsanitizer/asan/asan_win_weak_interception.cpp deleted file mode 100644 index 62534e12e2a6..000000000000 --- a/libsanitizer/asan/asan_win_weak_interception.cpp +++ /dev/null @@ -1,22 +0,0 @@ -//===-- asan_win_weak_interception.cpp ------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// This module should be included in Address Sanitizer when it is implemented as -// a shared library on Windows (dll), in order to delegate the calls of weak -// functions to the implementation in the main executable when a strong -// definition is provided. -//===----------------------------------------------------------------------===// -#ifdef SANITIZER_DYNAMIC -#include "sanitizer_common/sanitizer_win_weak_interception.h" -#include "asan_interface_internal.h" -// Check if strong definitions for weak functions are present in the main -// executable. If that is the case, override dll functions to point to strong -// implementations. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "asan_interface.inc" -#endif // SANITIZER_DYNAMIC diff --git a/libsanitizer/builtins/assembly.h b/libsanitizer/builtins/assembly.h index 169d49683f50..8c42fc773483 100644 --- a/libsanitizer/builtins/assembly.h +++ b/libsanitizer/builtins/assembly.h @@ -260,9 +260,10 @@ .globl name SEPARATOR \ SYMBOL_IS_FUNC(name) SEPARATOR \ DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR \ - CFI_START SEPARATOR \ DECLARE_FUNC_ENCODING \ - name: SEPARATOR BTI_C + name: \ + SEPARATOR CFI_START \ + SEPARATOR BTI_C #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \ .globl SYMBOL_NAME(name) SEPARATOR \ diff --git a/libsanitizer/hwasan/hwasan.cpp b/libsanitizer/hwasan/hwasan.cpp index 2f6cb10caf1b..24384d8b4d2c 100644 --- a/libsanitizer/hwasan/hwasan.cpp +++ b/libsanitizer/hwasan/hwasan.cpp @@ -357,8 +357,6 @@ __attribute__((constructor(0))) void __hwasan_init() { hwasan_init_is_running = 1; SanitizerToolName = "HWAddressSanitizer"; - InitTlsSize(); - CacheBinaryName(); InitializeFlags(); @@ -367,6 +365,8 @@ __attribute__((constructor(0))) void __hwasan_init() { __sanitizer_set_report_path(common_flags()->log_path); + InitializePlatformEarly(); + AndroidTestTlsSlot(); DisableCoreDumperIfNecessary(); @@ -678,6 +678,8 @@ uptr __hwasan_tag_pointer(uptr p, u8 tag) { return AddTagToPointer(p, tag); } +u8 __hwasan_get_tag_from_pointer(uptr p) { return GetTagFromPointer(p); } + void __hwasan_handle_longjmp(const void *sp_dst) { uptr dst = (uptr)sp_dst; // HWASan does not support tagged SP. @@ -690,7 +692,7 @@ void __hwasan_handle_longjmp(const void *sp_dst) { "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); + (void *)sp, (void *)dst, dst - sp, dst - sp); return; } TagMemory(sp, dst - sp, 0); diff --git a/libsanitizer/hwasan/hwasan.h b/libsanitizer/hwasan/hwasan.h index 37ef48222851..1ae463f845c8 100644 --- a/libsanitizer/hwasan/hwasan.h +++ b/libsanitizer/hwasan/hwasan.h @@ -104,9 +104,9 @@ static inline void *UntagPtr(const void *tagged_ptr) { } static inline uptr AddTagToPointer(uptr p, tag_t tag) { - return InTaggableRegion(p) - ? ((p & ~kAddressTagMask) | ((uptr)tag << kAddressTagShift)) - : p; + return InTaggableRegion(p) ? ((p & ~kAddressTagMask) | + ((uptr)(tag & kTagMask) << kAddressTagShift)) + : p; } namespace __hwasan { @@ -139,14 +139,14 @@ void hwasan_free(void *ptr, StackTrace *stack); void InstallAtExitHandler(); #define GET_MALLOC_STACK_TRACE \ - BufferedStackTrace stack; \ + UNINITIALIZED BufferedStackTrace stack; \ if (hwasan_inited) \ stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \ nullptr, common_flags()->fast_unwind_on_malloc, \ common_flags()->malloc_context_size) #define GET_FATAL_STACK_TRACE_PC_BP(pc, bp) \ - BufferedStackTrace stack; \ + UNINITIALIZED BufferedStackTrace stack; \ if (hwasan_inited) \ stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal) diff --git a/libsanitizer/hwasan/hwasan_allocation_functions.cpp b/libsanitizer/hwasan/hwasan_allocation_functions.cpp index 75d91ed09ce1..25ca0a3b0b68 100644 --- a/libsanitizer/hwasan/hwasan_allocation_functions.cpp +++ b/libsanitizer/hwasan/hwasan_allocation_functions.cpp @@ -17,7 +17,6 @@ #include "sanitizer_common/sanitizer_allocator_dlsym.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_mallinfo.h" -#include "sanitizer_common/sanitizer_tls_get_addr.h" using namespace __hwasan; @@ -62,10 +61,7 @@ void *__sanitizer_aligned_alloc(uptr alignment, uptr size) { SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer___libc_memalign(uptr alignment, uptr size) { GET_MALLOC_STACK_TRACE; - void *ptr = hwasan_memalign(alignment, size, &stack); - if (ptr) - DTLS_on_libc_memalign(ptr, size); - return ptr; + return hwasan_memalign(alignment, size, &stack); } SANITIZER_INTERFACE_ATTRIBUTE @@ -184,7 +180,7 @@ INTERCEPTOR_ALIAS(void *, malloc, SIZE_T size); 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(__sanitizer_struct_mallinfo, mallinfo,); INTERCEPTOR_ALIAS(int, mallopt, int cmd, int value); INTERCEPTOR_ALIAS(void, malloc_stats, void); # endif diff --git a/libsanitizer/hwasan/hwasan_allocator.cpp b/libsanitizer/hwasan/hwasan_allocator.cpp index d21ba024a20e..75dbb336e344 100644 --- a/libsanitizer/hwasan/hwasan_allocator.cpp +++ b/libsanitizer/hwasan/hwasan_allocator.cpp @@ -44,7 +44,7 @@ enum { // Initialized in HwasanAllocatorInit, an never changed. -static ALIGNED(16) u8 tail_magic[kShadowAlignment - 1]; +alignas(16) static u8 tail_magic[kShadowAlignment - 1]; static uptr max_malloc_size; bool HwasanChunkView::IsAllocated() const { @@ -289,6 +289,9 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { CHECK(tagged_ptr); void *untagged_ptr = UntagPtr(tagged_ptr); + if (RunFreeHooks(tagged_ptr)) + return; + if (CheckInvalidFree(stack, untagged_ptr, tagged_ptr)) return; @@ -302,8 +305,6 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { return; } - RunFreeHooks(tagged_ptr); - uptr orig_size = meta->GetRequestedSize(); u32 free_context_id = StackDepotPut(*stack); u32 alloc_context_id = meta->GetAllocStackId(); diff --git a/libsanitizer/hwasan/hwasan_checks.h b/libsanitizer/hwasan/hwasan_checks.h index 0911af30dcb8..735d21a5db77 100644 --- a/libsanitizer/hwasan/hwasan_checks.h +++ b/libsanitizer/hwasan/hwasan_checks.h @@ -140,7 +140,6 @@ __attribute__((always_inline, nodebug)) static inline uptr ShortTagSize( __attribute__((always_inline, nodebug)) static inline bool PossiblyShortTagMatches(tag_t mem_tag, uptr ptr, uptr sz) { - DCHECK(IsAligned(ptr, kShadowAlignment)); tag_t ptr_tag = GetTagFromPointer(ptr); if (ptr_tag == mem_tag) return true; diff --git a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp index 7642ba6c0bf0..48bc3b631ac0 100644 --- a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp +++ b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp @@ -36,15 +36,20 @@ decltype(__hwasan_shadow)* __hwasan_premap_shadow(); namespace __hwasan { +// We cannot call anything in libc here (see comment above), so we need to +// assume the biggest allowed page size. +// Android max page size is defined as 16k here: +// https://android.googlesource.com/platform/bionic/+/main/libc/platform/bionic/page.h#41 +static constexpr uptr kMaxGranularity = 16384; + // Conservative upper limit. static uptr PremapShadowSize() { - return RoundUpTo(GetMaxVirtualAddress() >> kShadowScale, - GetMmapGranularity()); + return RoundUpTo(GetMaxVirtualAddress() >> kShadowScale, kMaxGranularity); } static uptr PremapShadow() { return MapDynamicShadow(PremapShadowSize(), kShadowScale, - kShadowBaseAlignment, kHighMemEnd); + kShadowBaseAlignment, kHighMemEnd, kMaxGranularity); } static bool IsPremapShadowAvailable() { @@ -56,7 +61,7 @@ static bool IsPremapShadowAvailable() { } static uptr FindPremappedShadowStart(uptr shadow_size_bytes) { - const uptr granularity = GetMmapGranularity(); + const uptr granularity = kMaxGranularity; const uptr shadow_start = reinterpret_cast(&__hwasan_shadow); const uptr premap_shadow_size = PremapShadowSize(); const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity); @@ -109,7 +114,7 @@ uptr FindDynamicShadowStart(uptr shadow_size_bytes) { if (IsPremapShadowAvailable()) return FindPremappedShadowStart(shadow_size_bytes); return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment, - kHighMemEnd); + kHighMemEnd, kMaxGranularity); } } // namespace __hwasan @@ -135,7 +140,7 @@ uptr FindDynamicShadowStart(uptr shadow_size_bytes) { RingBufferSize()); # endif return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment, - kHighMemEnd); + kHighMemEnd, GetMmapGranularity()); } } // namespace __hwasan diff --git a/libsanitizer/hwasan/hwasan_flags.inc b/libsanitizer/hwasan/hwasan_flags.inc index 978fa46b705c..058a0457b9e7 100644 --- a/libsanitizer/hwasan/hwasan_flags.inc +++ b/libsanitizer/hwasan/hwasan_flags.inc @@ -84,3 +84,10 @@ HWASAN_FLAG(bool, malloc_bisect_dump, false, // are untagged before the call. HWASAN_FLAG(bool, fail_without_syscall_abi, true, "Exit if fail to request relaxed syscall ABI.") + +HWASAN_FLAG( + uptr, fixed_shadow_base, -1, + "If not -1, HWASan will attempt to allocate the shadow at this address, " + "instead of choosing one dynamically." + "Tip: this can be combined with the compiler option, " + "-hwasan-mapping-offset, to optimize the instrumentation.") diff --git a/libsanitizer/hwasan/hwasan_interceptors.cpp b/libsanitizer/hwasan/hwasan_interceptors.cpp index 96df4dd0c24d..c10b5c158548 100644 --- a/libsanitizer/hwasan/hwasan_interceptors.cpp +++ b/libsanitizer/hwasan/hwasan_interceptors.cpp @@ -334,10 +334,10 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, } # endif -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS -DEFINE_REAL(int, vfork) -DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork) +DEFINE_REAL(int, vfork,) +DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,) // Get and/or change the set of blocked signals. extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set, @@ -520,6 +520,7 @@ void InitializeInterceptors() { CHECK_EQ(inited, 0); # if HWASAN_WITH_INTERCEPTORS + __interception::DoesNotSupportStaticLinking(); InitializeCommonInterceptors(); (void)(read_iovec); diff --git a/libsanitizer/hwasan/hwasan_interface_internal.h b/libsanitizer/hwasan/hwasan_interface_internal.h index e7804cc49033..8f2f77dad917 100644 --- a/libsanitizer/hwasan/hwasan_interface_internal.h +++ b/libsanitizer/hwasan/hwasan_interface_internal.h @@ -160,6 +160,9 @@ 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_get_tag_from_pointer(uptr p); + SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_tag_mismatch(uptr addr, u8 ts); diff --git a/libsanitizer/hwasan/hwasan_linux.cpp b/libsanitizer/hwasan/hwasan_linux.cpp index 6f5e9432974e..68651d3d39d0 100644 --- a/libsanitizer/hwasan/hwasan_linux.cpp +++ b/libsanitizer/hwasan/hwasan_linux.cpp @@ -106,8 +106,22 @@ static uptr GetHighMemEnd() { } static void InitializeShadowBaseAddress(uptr shadow_size_bytes) { - __hwasan_shadow_memory_dynamic_address = - FindDynamicShadowStart(shadow_size_bytes); + // FIXME: Android should init flags before shadow. + if (!SANITIZER_ANDROID && flags()->fixed_shadow_base != (uptr)-1) { + __hwasan_shadow_memory_dynamic_address = flags()->fixed_shadow_base; + uptr beg = __hwasan_shadow_memory_dynamic_address; + uptr end = beg + shadow_size_bytes; + if (!MemoryRangeIsAvailable(beg, end)) { + Report( + "FATAL: HWAddressSanitizer: Shadow range %p-%p is not available.\n", + (void *)beg, (void *)end); + DumpProcessMap(); + CHECK(MemoryRangeIsAvailable(beg, end)); + } + } else { + __hwasan_shadow_memory_dynamic_address = + FindDynamicShadowStart(shadow_size_bytes); + } } static void MaybeDieIfNoTaggingAbi(const char *message) { @@ -246,9 +260,6 @@ bool InitShadow() { CHECK_GT(kLowShadowEnd, kLowShadowStart); CHECK_GT(kLowShadowStart, kLowMemEnd); - if (Verbosity()) - PrintAddressSpaceLayout(); - // Reserve shadow memory. ReserveShadowMemoryRange(kLowShadowStart, kLowShadowEnd, "low shadow"); ReserveShadowMemoryRange(kHighShadowStart, kHighShadowEnd, "high shadow"); @@ -262,6 +273,9 @@ bool InitShadow() { if (kHighShadowEnd + 1 < kHighMemStart) ProtectGap(kHighShadowEnd + 1, kHighMemStart - kHighShadowEnd - 1); + if (Verbosity()) + PrintAddressSpaceLayout(); + return true; } @@ -294,25 +308,6 @@ void InstallAtExitHandler() { atexit(HwasanAtExit); } // ---------------------- TSD ---------------- {{{1 -extern "C" void __hwasan_thread_enter() { - hwasanThreadList().CreateCurrentThread()->EnsureRandomStateInited(); -} - -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) { - // Block async signals on the thread as the handler can be instrumented. - // After this point instrumented code can't access essential data from TLS - // and will crash. - // Bionic already calls __hwasan_thread_exit with blocked signals. - if (SANITIZER_GLIBC) - BlockSignals(); - hwasanThreadList().ReleaseThread(t); - } -} - # if HWASAN_WITH_INTERCEPTORS static pthread_key_t tsd_key; static bool tsd_key_inited = false; @@ -504,12 +499,8 @@ void HwasanOnDeadlySignal(int signo, void *info, void *context) { } void Thread::InitStackAndTls(const InitState *) { - uptr tls_size; - uptr stack_size; - GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_size, &tls_begin_, - &tls_size); - stack_top_ = stack_bottom_ + stack_size; - tls_end_ = tls_begin_ + tls_size; + GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_top_, &tls_begin_, + &tls_end_); } uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) { @@ -536,16 +527,34 @@ uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) { return AddTagToPointer(p, tag); } +static void BeforeFork() { + VReport(2, "BeforeFork tid: %llu\n", GetTid()); + if (CAN_SANITIZE_LEAKS) { + __lsan::LockGlobal(); + } + // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the + // stuff we need. + __lsan::LockThreads(); + __lsan::LockAllocator(); + StackDepotLockBeforeFork(); +} + +static void AfterFork(bool fork_child) { + StackDepotUnlockAfterFork(fork_child); + // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock + // the stuff we need. + __lsan::UnlockAllocator(); + __lsan::UnlockThreads(); + if (CAN_SANITIZE_LEAKS) { + __lsan::UnlockGlobal(); + } + VReport(2, "AfterFork tid: %llu\n", GetTid()); +} + void HwasanInstallAtForkHandler() { - auto before = []() { - HwasanAllocatorLock(); - StackDepotLockAll(); - }; - auto after = []() { - StackDepotUnlockAll(); - HwasanAllocatorUnlock(); - }; - pthread_atfork(before, after, after); + pthread_atfork( + &BeforeFork, []() { AfterFork(/* fork_child= */ false); }, + []() { AfterFork(/* fork_child= */ true); }); } void InstallAtExitCheckLeaks() { @@ -561,4 +570,25 @@ void InstallAtExitCheckLeaks() { } // namespace __hwasan +using namespace __hwasan; + +extern "C" void __hwasan_thread_enter() { + hwasanThreadList().CreateCurrentThread()->EnsureRandomStateInited(); +} + +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) { + // Block async signals on the thread as the handler can be instrumented. + // After this point instrumented code can't access essential data from TLS + // and will crash. + // Bionic already calls __hwasan_thread_exit with blocked signals. + if (SANITIZER_GLIBC) + BlockSignals(); + hwasanThreadList().ReleaseThread(t); + } +} + #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD diff --git a/libsanitizer/hwasan/hwasan_preinit.cpp b/libsanitizer/hwasan/hwasan_preinit.cpp index 8c9c95f413be..8da47b5a2b78 100644 --- a/libsanitizer/hwasan/hwasan_preinit.cpp +++ b/libsanitizer/hwasan/hwasan_preinit.cpp @@ -14,10 +14,8 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #if SANITIZER_CAN_USE_PREINIT_ARRAY -// The symbol is called __local_hwasan_preinit, because it's not intended to -// be exported. -// This code linked into the main executable when -fsanitize=hwaddress is in -// the link flags. It can only use exported interface functions. -__attribute__((section(".preinit_array"), used)) static void ( - *__local_hwasan_preinit)(void) = __hwasan_init; +// This section is linked into the main executable when -fsanitize=hwaddress is +// specified to perform initialization at a very early stage. +__attribute__((section(".preinit_array"), used)) static auto preinit = + __hwasan_init; #endif diff --git a/libsanitizer/hwasan/hwasan_report.cpp b/libsanitizer/hwasan/hwasan_report.cpp index 5e8aa315801b..bc66e6e805c9 100644 --- a/libsanitizer/hwasan/hwasan_report.cpp +++ b/libsanitizer/hwasan/hwasan_report.cpp @@ -27,6 +27,7 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_mutex.h" +#include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_stacktrace_printer.h" @@ -40,7 +41,7 @@ class ScopedReport { public: explicit ScopedReport(bool fatal) : fatal(fatal) { Lock lock(&error_message_lock_); - error_message_ptr_ = fatal ? &error_message_ : nullptr; + error_message_ptr_ = &error_message_; ++hwasan_report_count; } @@ -205,6 +206,7 @@ static void PrintStackAllocations(const StackAllocationsRingBuffer *sa, tag_t addr_tag, uptr untagged_addr) { uptr frames = Min((uptr)flags()->stack_history_size, sa->size()); bool found_local = false; + InternalScopedString location; for (uptr i = 0; i < frames; i++) { const uptr *record_addr = &(*sa)[i]; uptr record = *record_addr; @@ -212,35 +214,104 @@ static void PrintStackAllocations(const StackAllocationsRingBuffer *sa, break; tag_t base_tag = reinterpret_cast(record_addr) >> kRecordAddrBaseTagShift; - uptr fp = (record >> kRecordFPShift) << kRecordFPLShift; + const uptr fp = (record >> kRecordFPShift) << kRecordFPLShift; + CHECK_LT(fp, kRecordFPModulus); uptr pc_mask = (1ULL << kRecordFPShift) - 1; uptr pc = record & pc_mask; FrameInfo frame; - if (Symbolizer::GetOrInit()->SymbolizeFrame(pc, &frame)) { - for (LocalInfo &local : frame.locals) { - if (!local.has_frame_offset || !local.has_size || !local.has_tag_offset) - continue; - tag_t obj_tag = base_tag ^ local.tag_offset; - if (obj_tag != addr_tag) - continue; - // Calculate the offset from the object address to the faulting - // address. Because we only store bits 4-19 of FP (bits 0-3 are - // guaranteed to be zero), the calculation is performed mod 2^20 and may - // harmlessly underflow if the address mod 2^20 is below the object - // address. - uptr obj_offset = - (untagged_addr - fp - local.frame_offset) & (kRecordFPModulus - 1); - if (obj_offset >= local.size) - continue; - if (!found_local) { - Printf("Potentially referenced stack objects:\n"); - found_local = true; + if (!Symbolizer::GetOrInit()->SymbolizeFrame(pc, &frame)) + continue; + for (LocalInfo &local : frame.locals) { + if (!local.has_frame_offset || !local.has_size || !local.has_tag_offset) + continue; + if (!(local.name && internal_strlen(local.name)) && + !(local.function_name && internal_strlen(local.function_name)) && + !(local.decl_file && internal_strlen(local.decl_file))) + continue; + tag_t obj_tag = base_tag ^ local.tag_offset; + if (obj_tag != addr_tag) + continue; + + // We only store bits 4-19 of FP (bits 0-3 are guaranteed to be zero). + // So we know only `FP % kRecordFPModulus`, and we can only calculate + // `local_beg % kRecordFPModulus`. + // Out of all possible `local_beg` we will only consider 2 candidates + // nearest to the `untagged_addr`. + uptr local_beg_mod = (fp + local.frame_offset) % kRecordFPModulus; + // Pick `local_beg` in the same 1 MiB block as `untagged_addr`. + uptr local_beg = + RoundDownTo(untagged_addr, kRecordFPModulus) + local_beg_mod; + // Pick the largest `local_beg <= untagged_addr`. It's either the current + // one or the one before. + if (local_beg > untagged_addr) + local_beg -= kRecordFPModulus; + + uptr offset = -1ull; + const char *whence; + const char *cause = nullptr; + uptr best_beg; + + // Try two 1 MiB blocks options and pick nearest one. + for (uptr i = 0; i < 2; ++i, local_beg += kRecordFPModulus) { + uptr local_end = local_beg + local.size; + if (local_beg > local_end) + continue; // This is a wraparound. + if (local_beg <= untagged_addr && untagged_addr < local_end) { + offset = untagged_addr - local_beg; + whence = "inside"; + cause = "use-after-scope"; + best_beg = local_beg; + break; // This is as close at it can be. + } + + if (untagged_addr >= local_end) { + uptr new_offset = untagged_addr - local_end; + if (new_offset < offset) { + offset = new_offset; + whence = "after"; + cause = "stack-buffer-overflow"; + best_beg = local_beg; + } + } else { + uptr new_offset = local_beg - untagged_addr; + if (new_offset < offset) { + offset = new_offset; + whence = "before"; + cause = "stack-buffer-overflow"; + best_beg = local_beg; + } } - Printf(" %s in %s %s:%d\n", local.name, local.function_name, - local.decl_file, local.decl_line); } - frame.Clear(); + + // To fail the `untagged_addr` must be near nullptr, which is impossible + // with Linux user space memory layout. + if (!cause) + continue; + + if (!found_local) { + Printf("\nPotentially referenced stack objects:\n"); + found_local = true; + } + + Decorator d; + Printf("%s", d.Error()); + Printf("Cause: %s\n", cause); + Printf("%s", d.Default()); + Printf("%s", d.Location()); + StackTracePrinter::GetOrInit()->RenderSourceLocation( + &location, local.decl_file, local.decl_line, /* column= */ 0, + common_flags()->symbolize_vs_style, + common_flags()->strip_path_prefix); + Printf( + "%p is located %zd bytes %s a %zd-byte local variable %s " + "[%p,%p) " + "in %s %s\n", + untagged_addr, offset, whence, local.size, local.name, best_beg, + best_beg + local.size, local.function_name, location.data()); + location.clear(); + Printf("%s\n", d.Default()); } + frame.Clear(); } if (found_local) @@ -257,14 +328,16 @@ static void PrintStackAllocations(const StackAllocationsRingBuffer *sa, break; uptr pc_mask = (1ULL << 48) - 1; uptr pc = record & pc_mask; - frame_desc.AppendF(" record_addr:0x%zx record:0x%zx", - reinterpret_cast(record_addr), record); - if (SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc)) { + frame_desc.AppendF(" record_addr:%p record:0x%zx", + reinterpret_cast(record_addr), record); + SymbolizedStackHolder symbolized_stack( + Symbolizer::GetOrInit()->SymbolizePC(pc)); + const SymbolizedStack *frame = symbolized_stack.get(); + if (frame) { StackTracePrinter::GetOrInit()->RenderFrame( &frame_desc, " %F %L", 0, frame->info.address, &frame->info, common_flags()->symbolize_vs_style, common_flags()->strip_path_prefix); - frame->ClearAll(); } Printf("%s\n", frame_desc.data()); frame_desc.clear(); @@ -353,7 +426,7 @@ static void PrintTagInfoAroundAddr(uptr addr, uptr num_rows, print_tag(s, row + i); s.Append(row + i == addr ? "]" : " "); } - s.AppendF("\n"); + s.Append("\n"); } } @@ -363,7 +436,7 @@ static void PrintTagsAroundAddr(uptr addr, GetTag get_tag, InternalScopedString s; addr = MemToShadow(addr); s.AppendF( - "Memory tags around the buggy address (one tag corresponds to %zd " + "\nMemory tags around the buggy address (one tag corresponds to %zd " "bytes):\n", kShadowAlignment); PrintTagInfoAroundAddr(addr, kShadowLines, s, @@ -383,10 +456,10 @@ static void PrintTagsAroundAddr(uptr addr, GetTag get_tag, tag_t short_tag = get_short_tag(tag_addr); s.AppendF("%02x", short_tag); } else { - s.AppendF(".."); + s.Append(".."); } }); - s.AppendF( + s.Append( "See " "https://clang.llvm.org/docs/" "HardwareAssistedAddressSanitizerDesign.html#short-granules for a " @@ -745,8 +818,6 @@ void BaseReport::PrintAddressDescription() const { // Check stack first. If the address is on the stack of a live thread, we // know it cannot be a heap / global overflow. for (const auto &sa : allocations.stack) { - // TODO(fmayer): figure out how to distinguish use-after-return and - // stack-buffer-overflow. Printf("%s", d.Error()); Printf("\nCause: stack tag-mismatch\n"); Printf("%s", d.Location()); @@ -803,8 +874,10 @@ void BaseReport::PrintAddressDescription() const { } // Print the remaining threads, as an extra information, 1 line per thread. - if (flags()->print_live_threads_info) + if (flags()->print_live_threads_info) { + Printf("\n"); hwasanThreadList().VisitAllLiveThreads([&](Thread *t) { t->Announce(); }); + } if (!num_descriptions_printed) // We exhausted our possibilities. Bail out. @@ -912,16 +985,16 @@ TailOverwrittenReport::~TailOverwrittenReport() { InternalScopedString s; u8 *tail = tail_copy; - s.AppendF("Tail contains: "); - for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.AppendF(".. "); + s.Append("Tail contains: "); + for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.Append(".. "); for (uptr i = 0; i < tail_size; i++) s.AppendF("%02x ", tail[i]); - s.AppendF("\n"); - s.AppendF("Expected: "); - for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.AppendF(".. "); + 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.AppendF("%02x ", actual_expected[i]); - s.AppendF("\n"); - s.AppendF(" "); - for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.AppendF(" "); + 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.AppendF("%s ", actual_expected[i] != tail[i] ? "^^" : " "); @@ -1020,7 +1093,7 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, // See the frame breakdown defined in __hwasan_tag_mismatch (from // hwasan_tag_mismatch_{aarch64,riscv64}.S). void ReportRegisters(const uptr *frame, uptr pc) { - Printf("Registers where the failure occurred (pc %p):\n", pc); + Printf("\nRegisters where the failure occurred (pc %p):\n", pc); // We explicitly print a single line (4 registers/line) each iteration to // reduce the amount of logcat error messages printed. Each Printf() will diff --git a/libsanitizer/hwasan/hwasan_thread.cpp b/libsanitizer/hwasan/hwasan_thread.cpp index ce36547580e6..8b32e4e760e2 100644 --- a/libsanitizer/hwasan/hwasan_thread.cpp +++ b/libsanitizer/hwasan/hwasan_thread.cpp @@ -68,6 +68,7 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, } Print("Creating : "); } + ClearShadowForThreadStackAndTLS(); } void Thread::InitStackRingBuffer(uptr stack_buffer_start, @@ -217,6 +218,11 @@ void GetAdditionalThreadContextPtrsLocked(InternalMmapVector *ptrs) { __hwasan::hwasanThreadArgRetval().GetAllPtrsLocked(ptrs); } -void GetRunningThreadsLocked(InternalMmapVector *threads) {} +void GetRunningThreadsLocked(InternalMmapVector *threads) { + // TODO: implement. +} +void PrintThreads() { + // TODO: implement. +} } // namespace __lsan diff --git a/libsanitizer/hwasan/hwasan_thread_list.cpp b/libsanitizer/hwasan/hwasan_thread_list.cpp index 7df4dd3d7851..794cfb7550d7 100644 --- a/libsanitizer/hwasan/hwasan_thread_list.cpp +++ b/libsanitizer/hwasan/hwasan_thread_list.cpp @@ -1,5 +1,6 @@ #include "hwasan_thread_list.h" +#include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_thread_arg_retval.h" namespace __hwasan { @@ -13,15 +14,15 @@ ThreadArgRetval &hwasanThreadArgRetval() { return *thread_data; } void InitThreadList(uptr storage, uptr size) { CHECK_EQ(hwasan_thread_list, nullptr); - static ALIGNED(alignof( - HwasanThreadList)) char thread_list_placeholder[sizeof(HwasanThreadList)]; + alignas(alignof(HwasanThreadList)) static char + thread_list_placeholder[sizeof(HwasanThreadList)]; hwasan_thread_list = new (thread_list_placeholder) HwasanThreadList(storage, size); CHECK_EQ(thread_data, nullptr); - static ALIGNED(alignof( - ThreadArgRetval)) char thread_data_placeholder[sizeof(ThreadArgRetval)]; + alignas(alignof(ThreadArgRetval)) static char + thread_data_placeholder[sizeof(ThreadArgRetval)]; thread_data = new (thread_data_placeholder) ThreadArgRetval(); } diff --git a/libsanitizer/hwasan/hwasan_thread_list.h b/libsanitizer/hwasan/hwasan_thread_list.h index 82f6c70a03f8..369a1c3d6f5f 100644 --- a/libsanitizer/hwasan/hwasan_thread_list.h +++ b/libsanitizer/hwasan/hwasan_thread_list.h @@ -18,7 +18,7 @@ // * Start of the shadow memory region is aligned to 2**kShadowBaseAlignment. // * All stack ring buffers are located within (2**kShadowBaseAlignment) // sized region below and adjacent to the shadow region. -// * Each ring buffer has a size of (2**N)*4096 where N is in [0, 8), and is +// * Each ring buffer has a size of (2**N)*4096 where N is in [0, 7), and is // aligned to twice its size. The value of N can be different for each buffer. // // These constrains guarantee that, given an address A of any element of the @@ -47,7 +47,6 @@ #include "hwasan_allocator.h" #include "hwasan_flags.h" #include "hwasan_thread.h" -#include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_thread_arg_retval.h" namespace __hwasan { @@ -56,7 +55,10 @@ static uptr RingBufferSize() { uptr desired_bytes = flags()->stack_history_size * sizeof(uptr); // FIXME: increase the limit to 8 once this bug is fixed: // https://bugs.llvm.org/show_bug.cgi?id=39030 - for (int shift = 1; shift < 7; ++shift) { + // Note that we *cannot* do that on Android, as the runtime will indefinitely + // have to support code that is compiled with ashr, which only works with + // shifts up to 6. + for (int shift = 0; shift < 7; ++shift) { uptr size = 4096 * (1ULL << shift); if (size >= desired_bytes) return size; diff --git a/libsanitizer/include/sanitizer/allocator_interface.h b/libsanitizer/include/sanitizer/allocator_interface.h index a792e9f0136e..1696a92681e3 100644 --- a/libsanitizer/include/sanitizer/allocator_interface.h +++ b/libsanitizer/include/sanitizer/allocator_interface.h @@ -62,13 +62,20 @@ size_t SANITIZER_CDECL __sanitizer_get_free_bytes(void); size_t SANITIZER_CDECL __sanitizer_get_unmapped_bytes(void); /* Malloc hooks that may be optionally provided by user. - __sanitizer_malloc_hook(ptr, size) is called immediately after - allocation of "size" bytes, which returned "ptr". - __sanitizer_free_hook(ptr) is called immediately before - deallocation of "ptr". */ + - __sanitizer_malloc_hook(ptr, size) is called immediately after allocation + of "size" bytes, which returned "ptr". + - __sanitizer_free_hook(ptr) is called immediately before deallocation of + "ptr". + - __sanitizer_ignore_free_hook(ptr) is called immediately before deallocation + of "ptr", and if it returns a non-zero value, the deallocation of "ptr" + will not take place. This allows software to make free a no-op until it + calls free() again in the same pointer at a later time. Hint: read this as + "ignore the free" rather than "ignore the hook". +*/ void SANITIZER_CDECL __sanitizer_malloc_hook(const volatile void *ptr, size_t size); void SANITIZER_CDECL __sanitizer_free_hook(const volatile void *ptr); +int SANITIZER_CDECL __sanitizer_ignore_free_hook(const volatile void *ptr); /* Installs a pair of hooks for malloc/free. Several (currently, 5) hook pairs may be installed, they are executed diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h index 56d9e008fa06..57313f9bc80e 100644 --- a/libsanitizer/include/sanitizer/common_interface_defs.h +++ b/libsanitizer/include/sanitizer/common_interface_defs.h @@ -193,6 +193,43 @@ void SANITIZER_CDECL __sanitizer_annotate_double_ended_contiguous_container( const void *old_container_beg, const void *old_container_end, const void *new_container_beg, const void *new_container_end); +/// Copies memory annotations from a source storage region to a destination +/// storage region. After the operation, the destination region has the same +/// memory annotations as the source region, as long as sanitizer limitations +/// allow it (more bytes may be unpoisoned than in the source region, resulting +/// in more false negatives, but never false positives). If the source and +/// destination regions overlap, only the minimal required changes are made to +/// preserve the correct annotations. Old storage bytes that are not in the new +/// storage should have the same annotations, as long as sanitizer limitations +/// allow it. +/// +/// This function is primarily designed to be used when moving trivially +/// relocatable objects that may have poisoned memory, making direct copying +/// problematic under sanitizer. However, this function does not move memory +/// content itself, only annotations. +/// +/// A contiguous container is a container that keeps all of its elements in a +/// contiguous region of memory. The container owns the region of memory +/// [src_begin, src_end) and [dst_begin, dst_end). The memory +/// within these regions may be alternately poisoned and non-poisoned, with +/// possibly smaller poisoned and unpoisoned regions. +/// +/// If this function fully poisons a granule, it is marked as "container +/// overflow". +/// +/// Argument requirements: The destination container must have the same size as +/// the source container, which is inferred from the beginning and end of the +/// source region. Addresses may be granule-unaligned, but this may affect +/// performance. +/// +/// \param src_begin Begin of the source container region. +/// \param src_end End of the source container region. +/// \param dst_begin Begin of the destination container region. +/// \param dst_end End of the destination container region. +void SANITIZER_CDECL __sanitizer_copy_contiguous_container_annotations( + const void *src_begin, const void *src_end, const void *dst_begin, + const void *dst_end); + /// Returns true if the contiguous container [beg, end) is properly /// poisoned. /// @@ -293,7 +330,7 @@ void SANITIZER_CDECL __sanitizer_symbolize_global(void *data_ptr, #define __sanitizer_return_address() \ __builtin_extract_return_addr(__builtin_return_address(0)) #else -void *SANITIZER_CDECL _ReturnAddress(void); +void *_ReturnAddress(void); #pragma intrinsic(_ReturnAddress) #define __sanitizer_return_address() _ReturnAddress() #endif diff --git a/libsanitizer/include/sanitizer/hwasan_interface.h b/libsanitizer/include/sanitizer/hwasan_interface.h index abe310c06669..407f488a24a6 100644 --- a/libsanitizer/include/sanitizer/hwasan_interface.h +++ b/libsanitizer/include/sanitizer/hwasan_interface.h @@ -44,6 +44,10 @@ void SANITIZER_CDECL __hwasan_tag_memory(const volatile void *p, void *SANITIZER_CDECL __hwasan_tag_pointer(const volatile void *p, unsigned char tag); +/// Get tag from the pointer. +unsigned char SANITIZER_CDECL +__hwasan_get_tag_from_pointer(const volatile void *p); + // 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; diff --git a/libsanitizer/include/sanitizer/linux_syscall_hooks.h b/libsanitizer/include/sanitizer/linux_syscall_hooks.h index 3f3f1e78dfb8..5f262455cb94 100644 --- a/libsanitizer/include/sanitizer/linux_syscall_hooks.h +++ b/libsanitizer/include/sanitizer/linux_syscall_hooks.h @@ -1856,6 +1856,15 @@ __sanitizer_syscall_pre_impl_sigaltstack((long)ss, (long)oss) #define __sanitizer_syscall_post_sigaltstack(res, ss, oss) \ __sanitizer_syscall_post_impl_sigaltstack(res, (long)ss, (long)oss) +#define __sanitizer_syscall_pre_futex(uaddr, futex_op, val, timeout, uaddr2, \ + val3) \ + __sanitizer_syscall_pre_impl_futex((long)uaddr, (long)futex_op, (long)val, \ + (long)timeout, (long)uaddr2, (long)val3) +#define __sanitizer_syscall_post_futex(res, uaddr, futex_op, val, timeout, \ + uaddr2, val3) \ + __sanitizer_syscall_post_impl_futex(res, (long)uaddr, (long)futex_op, \ + (long)val, (long)timeout, (long)uaddr2, \ + (long)val3) // And now a few syscalls we don't handle yet. #define __sanitizer_syscall_pre_afs_syscall(...) @@ -1875,7 +1884,6 @@ #define __sanitizer_syscall_pre_fchown32(...) #define __sanitizer_syscall_pre_ftime(...) #define __sanitizer_syscall_pre_ftruncate64(...) -#define __sanitizer_syscall_pre_futex(...) #define __sanitizer_syscall_pre_getegid32(...) #define __sanitizer_syscall_pre_geteuid32(...) #define __sanitizer_syscall_pre_getgid32(...) @@ -1954,7 +1962,6 @@ #define __sanitizer_syscall_post_fchown32(res, ...) #define __sanitizer_syscall_post_ftime(res, ...) #define __sanitizer_syscall_post_ftruncate64(res, ...) -#define __sanitizer_syscall_post_futex(res, ...) #define __sanitizer_syscall_post_getegid32(res, ...) #define __sanitizer_syscall_post_geteuid32(res, ...) #define __sanitizer_syscall_post_getgid32(res, ...) @@ -3093,6 +3100,11 @@ void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act, long oldact, long sz); void __sanitizer_syscall_pre_impl_sigaltstack(long ss, long oss); void __sanitizer_syscall_post_impl_sigaltstack(long res, long ss, long oss); +void __sanitizer_syscall_pre_impl_futex(long uaddr, long futex_op, long val, + long timeout, long uaddr2, long val3); +void __sanitizer_syscall_post_impl_futex(long res, long uaddr, long futex_op, + long val, long timeout, long uaddr2, + long val3); #ifdef __cplusplus } // extern "C" #endif diff --git a/libsanitizer/include/sanitizer/memprof_interface.h b/libsanitizer/include/sanitizer/memprof_interface.h index fe0a2fc5ef02..4660a7818c92 100644 --- a/libsanitizer/include/sanitizer/memprof_interface.h +++ b/libsanitizer/include/sanitizer/memprof_interface.h @@ -59,6 +59,12 @@ const char *SANITIZER_CDECL __memprof_default_options(void); /// \returns 0 on success. int SANITIZER_CDECL __memprof_profile_dump(void); +/// Closes the existing file descriptor, if it is valid and not stdout or +/// stderr, and resets the internal state such that the profile filename is +/// reopened on the next profile dump attempt. This can be used to enable +/// multiple rounds of profiling on the same binary. +void SANITIZER_CDECL __memprof_profile_reset(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/libsanitizer/include/sanitizer/nsan_interface.h b/libsanitizer/include/sanitizer/nsan_interface.h new file mode 100644 index 000000000000..057ca0473bb3 --- /dev/null +++ b/libsanitizer/include/sanitizer/nsan_interface.h @@ -0,0 +1,75 @@ +//===-- sanitizer/nsan_interface.h ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Public interface for nsan. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_NSAN_INTERFACE_H +#define SANITIZER_NSAN_INTERFACE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// User-provided default option settings. +/// +/// You can provide your own implementation of this function to return a string +/// containing NSan runtime options (for example, +/// verbosity=1:halt_on_error=0). +/// +/// \returns Default options string. +const char *__nsan_default_options(void); + +// Dumps nsan shadow data for a block of `size_bytes` bytes of application +// memory at location `addr`. +// +// Each line contains application address, shadow types, then values. +// Unknown types are shown as `__`, while known values are shown as +// `f`, `d`, `l` for float, double, and long double respectively. Position is +// shown as a single hex digit. The shadow value itself appears on the line that +// contains the first byte of the value. +// FIXME: Show both shadow and application value. +// +// Example: `__nsan_dump_shadow_mem(addr, 32, 8, 0)` might print: +// +// 0x0add7359: __ f0 f1 f2 f3 __ __ __ (42.000) +// 0x0add7361: __ d1 d2 d3 d4 d5 d6 d7 +// 0x0add7369: d8 f0 f1 f2 f3 __ __ f2 (-1.000) (12.5) +// 0x0add7371: f3 __ __ __ __ __ __ __ +// +// This means that there is: +// - a shadow double for the float at address 0x0add7360, with value 42; +// - a shadow float128 for the double at address 0x0add7362, with value -1; +// - a shadow double for the float at address 0x0add736a, with value 12.5; +// There was also a shadow double for the float at address 0x0add736e, but bytes +// f0 and f1 were overwritten by one or several stores, so that the shadow value +// is no longer valid. +// The argument `reserved` can be any value. Its true value is provided by the +// instrumentation. +void __nsan_dump_shadow_mem(const char *addr, size_t size_bytes, + size_t bytes_per_line, size_t reserved); + +// Explicitly dumps a value. +// FIXME: vector versions ? +void __nsan_dump_float(float value); +void __nsan_dump_double(double value); +void __nsan_dump_longdouble(long double value); + +// Explicitly checks a value. +// FIXME: vector versions ? +void __nsan_check_float(float value); +void __nsan_check_double(double value); +void __nsan_check_longdouble(long double value); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // SANITIZER_NSAN_INTERFACE_H diff --git a/libsanitizer/include/sanitizer/rtsan_interface.h b/libsanitizer/include/sanitizer/rtsan_interface.h new file mode 100644 index 000000000000..5d7ce5345712 --- /dev/null +++ b/libsanitizer/include/sanitizer/rtsan_interface.h @@ -0,0 +1,75 @@ +//===-- sanitizer/rtsan_interface.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of RealtimeSanitizer. +// +// Public interface header. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_RTSAN_INTERFACE_H +#define SANITIZER_RTSAN_INTERFACE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Disable all RTSan error reporting. +// Must be paired with a call to `__rtsan_enable` +void SANITIZER_CDECL __rtsan_disable(void); + +// Re-enable all RTSan error reporting. +// Must follow a call to `__rtsan_disable`. +void SANITIZER_CDECL __rtsan_enable(void); + +#ifdef __cplusplus +} // extern "C" + +namespace __rtsan { +#if defined(__has_feature) && __has_feature(realtime_sanitizer) + +class ScopedDisabler { +public: + ScopedDisabler() { __rtsan_disable(); } + ~ScopedDisabler() { __rtsan_enable(); } + +#if __cplusplus >= 201103L + ScopedDisabler(const ScopedDisabler &) = delete; + ScopedDisabler &operator=(const ScopedDisabler &) = delete; + ScopedDisabler(ScopedDisabler &&) = delete; + ScopedDisabler &operator=(ScopedDisabler &&) = delete; +#else +private: + ScopedDisabler(const ScopedDisabler &); + ScopedDisabler &operator=(const ScopedDisabler &); +#endif // __cplusplus >= 201103L +}; + +#else + +class ScopedDisabler { +public: + ScopedDisabler() {} +#if __cplusplus >= 201103L + ScopedDisabler(const ScopedDisabler &) = delete; + ScopedDisabler &operator=(const ScopedDisabler &) = delete; + ScopedDisabler(ScopedDisabler &&) = delete; + ScopedDisabler &operator=(ScopedDisabler &&) = delete; +#else +private: + ScopedDisabler(const ScopedDisabler &); + ScopedDisabler &operator=(const ScopedDisabler &); +#endif // __cplusplus >= 201103L +}; + +#endif // defined(__has_feature) && __has_feature(realtime_sanitizer) +} // namespace __rtsan +#endif // __cplusplus + +#endif // SANITIZER_RTSAN_INTERFACE_H diff --git a/libsanitizer/include/sanitizer/ubsan_interface.h b/libsanitizer/include/sanitizer/ubsan_interface.h index 435eb1ae332c..30a7fd875043 100644 --- a/libsanitizer/include/sanitizer/ubsan_interface.h +++ b/libsanitizer/include/sanitizer/ubsan_interface.h @@ -13,6 +13,8 @@ #ifndef SANITIZER_UBSAN_INTERFACE_H #define SANITIZER_UBSAN_INTERFACE_H +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/libsanitizer/interception/interception.h b/libsanitizer/interception/interception.h index 73135b34bee2..0580d97edda6 100644 --- a/libsanitizer/interception/interception.h +++ b/libsanitizer/interception/interception.h @@ -25,8 +25,19 @@ // These typedefs should be used only in the interceptor definitions to replace // the standard system types (e.g. SSIZE_T instead of ssize_t) -typedef __sanitizer::uptr SIZE_T; -typedef __sanitizer::sptr SSIZE_T; +// On Windows the system headers (basetsd.h) provide a conflicting definition +// of SIZE_T/SSIZE_T that do not match the real size_t/ssize_t for 32-bit +// systems (using long instead of the expected int). Work around the typedef +// redefinition by #defining SIZE_T instead of using a typedef. +// TODO: We should be using __sanitizer::usize (and a new ssize) instead of +// these new macros as long as we ensure they match the real system definitions. +#if SANITIZER_WINDOWS +// Ensure that (S)SIZE_T were already defined as we are about to override them. +# include +#endif + +#define SIZE_T __sanitizer::usize +#define SSIZE_T __sanitizer::sptr typedef __sanitizer::sptr PTRDIFF_T; typedef __sanitizer::s64 INTMAX_T; typedef __sanitizer::u64 UINTMAX_T; @@ -338,16 +349,20 @@ const interpose_substitution substitution_##func_name[] \ #endif // ISO C++ forbids casting between pointer-to-function and pointer-to-object, -// so we use casting via an integral type __interception::uptr, -// assuming that system is POSIX-compliant. Using other hacks seem -// challenging, as we don't even pass function type to -// INTERCEPT_FUNCTION macro, only its name. +// so we use casts via uintptr_t (the local __sanitizer::uptr equivalent). namespace __interception { -#if defined(_WIN64) -typedef unsigned long long uptr; + +#if defined(__ELF__) && !SANITIZER_FUCHSIA +// The use of interceptors makes many sanitizers unusable for static linking. +// Define a function, if called, will cause a linker error (undefined _DYNAMIC). +// However, -static-pie (which is not common) cannot be detected at link time. +extern uptr kDynamic[] asm("_DYNAMIC"); +inline void DoesNotSupportStaticLinking() { + [[maybe_unused]] volatile auto x = &kDynamic; +} #else -typedef unsigned long uptr; -#endif // _WIN64 +inline void DoesNotSupportStaticLinking() {} +#endif } // namespace __interception #define INCLUDED_FROM_INTERCEPTION_LIB diff --git a/libsanitizer/interception/interception_linux.h b/libsanitizer/interception/interception_linux.h index 433a3d9bd7fa..2e01ff44578c 100644 --- a/libsanitizer/interception/interception_linux.h +++ b/libsanitizer/interception/interception_linux.h @@ -28,12 +28,14 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, uptr func, uptr trampoline); } // namespace __interception -#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \ - ::__interception::InterceptFunction( \ - #func, \ - (::__interception::uptr *)&REAL(func), \ - (::__interception::uptr)&(func), \ - (::__interception::uptr)&TRAMPOLINE(func)) +// Cast func to type of REAL(func) before casting to uptr in case it is an +// overloaded function, which is the case for some glibc functions when +// _FORTIFY_SOURCE is used. This disambiguates which overload to use. +#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \ + ::__interception::InterceptFunction( \ + #func, (::__interception::uptr *)&REAL(func), \ + (::__interception::uptr)(decltype(REAL(func)))&(func), \ + (::__interception::uptr) &TRAMPOLINE(func)) // dlvsym is a GNU extension supported by some other platforms. #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD @@ -41,7 +43,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, ::__interception::InterceptFunction( \ #func, symver, \ (::__interception::uptr *)&REAL(func), \ - (::__interception::uptr)&(func), \ + (::__interception::uptr)(decltype(REAL(func)))&(func), \ (::__interception::uptr)&TRAMPOLINE(func)) #else #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ diff --git a/libsanitizer/interception/interception_type_test.cpp b/libsanitizer/interception/interception_type_test.cpp index 7c3de82a1e86..41041ce6f95c 100644 --- a/libsanitizer/interception/interception_type_test.cpp +++ b/libsanitizer/interception/interception_type_test.cpp @@ -12,28 +12,35 @@ //===----------------------------------------------------------------------===// #include "interception.h" +#include "sanitizer_common/sanitizer_type_traits.h" -#if SANITIZER_LINUX || SANITIZER_APPLE - -#include +#if __has_include() +# include +#endif #include #include -COMPILER_CHECK(sizeof(::SIZE_T) == sizeof(size_t)); -COMPILER_CHECK(sizeof(::SSIZE_T) == sizeof(ssize_t)); -COMPILER_CHECK(sizeof(::PTRDIFF_T) == sizeof(ptrdiff_t)); +COMPILER_CHECK((__sanitizer::is_same<__sanitizer::uptr, ::uintptr_t>::value)); +COMPILER_CHECK((__sanitizer::is_same<__sanitizer::sptr, ::intptr_t>::value)); +COMPILER_CHECK((__sanitizer::is_same<__sanitizer::usize, ::size_t>::value)); +COMPILER_CHECK((__sanitizer::is_same<::PTRDIFF_T, ::ptrdiff_t>::value)); +COMPILER_CHECK((__sanitizer::is_same<::SIZE_T, ::size_t>::value)); +#if !SANITIZER_WINDOWS +// No ssize_t on Windows. +COMPILER_CHECK((__sanitizer::is_same<::SSIZE_T, ::ssize_t>::value)); +#endif +// TODO: These are not actually the same type on Linux (long vs long long) COMPILER_CHECK(sizeof(::INTMAX_T) == sizeof(intmax_t)); +COMPILER_CHECK(sizeof(::UINTMAX_T) == sizeof(uintmax_t)); -# if SANITIZER_GLIBC || SANITIZER_ANDROID +#if SANITIZER_GLIBC || SANITIZER_ANDROID COMPILER_CHECK(sizeof(::OFF64_T) == sizeof(off64_t)); -# endif +#endif // The following are the cases when pread (and friends) is used instead of // pread64. In those cases we need OFF_T to match off_t. We don't care about the // rest (they depend on _FILE_OFFSET_BITS setting when building an application). -# if SANITIZER_ANDROID || !defined _FILE_OFFSET_BITS || \ - _FILE_OFFSET_BITS != 64 +#if !SANITIZER_WINDOWS && (SANITIZER_ANDROID || !defined _FILE_OFFSET_BITS || \ + _FILE_OFFSET_BITS != 64) COMPILER_CHECK(sizeof(::OFF_T) == sizeof(off_t)); -# endif - #endif diff --git a/libsanitizer/interception/interception_win.cpp b/libsanitizer/interception/interception_win.cpp index 1b681ada37b1..077a536dd2a3 100644 --- a/libsanitizer/interception/interception_win.cpp +++ b/libsanitizer/interception/interception_win.cpp @@ -27,7 +27,7 @@ // // 1) Detour // -// The Detour hooking technique is assuming the presence of an header with +// The Detour hooking technique is assuming the presence of a header with // padding and an overridable 2-bytes nop instruction (mov edi, edi). The // nop instruction can safely be replaced by a 2-bytes jump without any need // to save the instruction. A jump to the target is encoded in the function @@ -47,7 +47,7 @@ // // func: jmp