aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-19 10:05:08 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-19 10:05:08 +0000
commit0646903fc1f75f6e605754621119473ee083f4a4 (patch)
tree57bce79a7423a054cccec23bdf6cd96e2d271b4a
parent005b7ed8f76756d94ef6266ded755ab7863cb936 (diff)
downloadsrc-0646903fc1f75f6e605754621119473ee083f4a4.tar.gz
src-0646903fc1f75f6e605754621119473ee083f4a4.zip
Vendor import of compiler-rt trunk r351319 (just before the release_80vendor/compiler-rt/compiler-rt-trunk-r351319vendor/compiler-rt/compiler-rt-release_80-r351543
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=343175 svn path=/vendor/compiler-rt/compiler-rt-release_80-r351543/; revision=343195; tag=vendor/compiler-rt/compiler-rt-release_80-r351543
-rw-r--r--CMakeLists.txt97
-rw-r--r--LICENSE.TXT2
-rw-r--r--cmake/Modules/AddCompilerRT.cmake40
-rw-r--r--cmake/Modules/CompilerRTUtils.cmake141
-rw-r--r--cmake/Modules/HandleCompilerRT.cmake4
-rw-r--r--cmake/Modules/SanitizerUtils.cmake14
-rw-r--r--cmake/base-config-ix.cmake16
-rw-r--r--cmake/builtin-config-ix.cmake14
-rw-r--r--cmake/config-ix.cmake44
-rw-r--r--include/sanitizer/allocator_interface.h1
-rw-r--r--include/sanitizer/common_interface_defs.h6
-rw-r--r--include/sanitizer/hwasan_interface.h51
-rw-r--r--include/sanitizer/netbsd_syscall_hooks.h46
-rw-r--r--include/xray/xray_log_interface.h25
-rw-r--r--lib/asan/CMakeLists.txt40
-rw-r--r--lib/asan/asan_allocator.h41
-rw-r--r--lib/asan/asan_errors.cc5
-rw-r--r--lib/asan/asan_errors.h7
-rw-r--r--lib/asan/asan_flags.inc2
-rw-r--r--lib/asan/asan_fuchsia.cc7
-rw-r--r--lib/asan/asan_globals.cc17
-rw-r--r--lib/asan/asan_globals_win.cc2
-rw-r--r--lib/asan/asan_internal.h5
-rw-r--r--lib/asan/asan_linux.cc7
-rw-r--r--lib/asan/asan_malloc_linux.cc2
-rw-r--r--lib/asan/asan_malloc_mac.cc21
-rw-r--r--lib/asan/asan_malloc_win.cc21
-rw-r--r--lib/asan/asan_new_delete.cc2
-rw-r--r--lib/asan/asan_posix.cc46
-rw-r--r--lib/asan/asan_report.h4
-rw-r--r--lib/asan/asan_rtems.cc6
-rw-r--r--lib/asan/asan_rtl.cc25
-rw-r--r--lib/asan/asan_thread.cc24
-rw-r--r--lib/asan/asan_win.cc15
-rw-r--r--lib/asan/asan_win_dll_thunk.cc1
-rwxr-xr-xlib/asan/scripts/asan_symbolize.py6
-rw-r--r--lib/asan/tests/CMakeLists.txt5
-rw-r--r--lib/asan/tests/asan_interface_test.cc2
-rw-r--r--lib/asan/tests/asan_noinst_test.cc2
-rw-r--r--lib/asan/tests/asan_test.cc2
-rw-r--r--lib/builtins/CMakeLists.txt2
-rw-r--r--lib/builtins/Darwin-excludes/10.4.txt137
-rw-r--r--lib/builtins/arm/addsf3.S2
-rw-r--r--lib/builtins/arm/aeabi_cdcmp.S6
-rw-r--r--lib/builtins/arm/aeabi_cfcmp.S6
-rw-r--r--lib/builtins/clzdi2.c9
-rw-r--r--lib/builtins/cpu_model.c113
-rw-r--r--lib/builtins/ctzdi2.c9
-rw-r--r--lib/builtins/divdc3.c4
-rw-r--r--lib/builtins/divdf3.c46
-rw-r--r--lib/builtins/divsc3.c5
-rw-r--r--lib/builtins/divsf3.c40
-rw-r--r--lib/builtins/divtc3.c5
-rw-r--r--lib/builtins/emutls.c13
-rw-r--r--lib/builtins/fp_lib.h57
-rw-r--r--lib/builtins/gcc_personality_v0.c5
-rw-r--r--lib/builtins/int_lib.h2
-rw-r--r--lib/builtins/int_math.h4
-rw-r--r--lib/builtins/int_types.h23
-rw-r--r--lib/builtins/int_util.c8
-rw-r--r--lib/builtins/int_util.h6
-rw-r--r--lib/builtins/os_version_check.c41
-rw-r--r--lib/builtins/ppc/divtc3.c12
-rw-r--r--lib/builtins/ppc/fixunstfti.c106
-rw-r--r--lib/builtins/ppc/floattitf.c48
-rw-r--r--lib/cfi/CMakeLists.txt2
-rw-r--r--lib/cfi/cfi.cc40
-rw-r--r--lib/cfi/cfi_blacklist.txt6
-rw-r--r--lib/dfsan/dfsan.cc2
-rw-r--r--lib/esan/CMakeLists.txt1
-rw-r--r--lib/esan/esan_interceptors.cpp10
-rw-r--r--lib/esan/esan_shadow.h2
-rw-r--r--lib/esan/esan_sideline.h1
-rw-r--r--lib/esan/esan_sideline_bsd.cpp35
-rw-r--r--lib/fuzzer/CMakeLists.txt6
-rw-r--r--lib/fuzzer/FuzzerBuiltins.h36
-rw-r--r--lib/fuzzer/FuzzerBuiltinsMsvc.h59
-rw-r--r--lib/fuzzer/FuzzerCommand.h4
-rw-r--r--lib/fuzzer/FuzzerCorpus.h6
-rw-r--r--lib/fuzzer/FuzzerDefs.h19
-rw-r--r--lib/fuzzer/FuzzerDriver.cpp5
-rw-r--r--lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp62
-rw-r--r--lib/fuzzer/FuzzerExtFunctionsWeak.cpp2
-rw-r--r--lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp56
-rw-r--r--lib/fuzzer/FuzzerExtFunctionsWindows.cpp83
-rw-r--r--lib/fuzzer/FuzzerFlags.def12
-rw-r--r--lib/fuzzer/FuzzerIO.cpp12
-rw-r--r--lib/fuzzer/FuzzerIO.h2
-rw-r--r--lib/fuzzer/FuzzerIOPosix.cpp7
-rw-r--r--lib/fuzzer/FuzzerIOWindows.cpp22
-rw-r--r--lib/fuzzer/FuzzerInternal.h1
-rw-r--r--lib/fuzzer/FuzzerLoop.cpp47
-rw-r--r--lib/fuzzer/FuzzerMutate.cpp58
-rw-r--r--lib/fuzzer/FuzzerMutate.h8
-rw-r--r--lib/fuzzer/FuzzerOptions.h3
-rw-r--r--lib/fuzzer/FuzzerTracePC.cpp160
-rw-r--r--lib/fuzzer/FuzzerTracePC.h20
-rw-r--r--lib/fuzzer/FuzzerUtil.h6
-rw-r--r--lib/fuzzer/FuzzerUtilFuchsia.cpp32
-rw-r--r--lib/fuzzer/FuzzerUtilWindows.cpp6
-rw-r--r--lib/fuzzer/afl/afl_driver.cpp2
-rw-r--r--lib/fuzzer/tests/CMakeLists.txt8
-rw-r--r--lib/fuzzer/tests/FuzzerUnittest.cpp7
-rw-r--r--lib/hwasan/CMakeLists.txt38
-rw-r--r--lib/hwasan/hwasan.cc271
-rw-r--r--lib/hwasan/hwasan.h36
-rw-r--r--lib/hwasan/hwasan_allocator.cc348
-rw-r--r--lib/hwasan/hwasan_allocator.h77
-rw-r--r--lib/hwasan/hwasan_checks.h80
-rw-r--r--lib/hwasan/hwasan_dynamic_shadow.cc30
-rw-r--r--lib/hwasan/hwasan_flags.h2
-rw-r--r--lib/hwasan/hwasan_flags.inc57
-rw-r--r--lib/hwasan/hwasan_interceptors.cc333
-rw-r--r--lib/hwasan/hwasan_interface_internal.h75
-rw-r--r--lib/hwasan/hwasan_linux.cc231
-rw-r--r--lib/hwasan/hwasan_mapping.h63
-rw-r--r--lib/hwasan/hwasan_memintrinsics.cc45
-rw-r--r--lib/hwasan/hwasan_new_delete.cc2
-rw-r--r--lib/hwasan/hwasan_poisoning.cc6
-rw-r--r--lib/hwasan/hwasan_poisoning.h2
-rw-r--r--lib/hwasan/hwasan_report.cc412
-rw-r--r--lib/hwasan/hwasan_report.h8
-rw-r--r--lib/hwasan/hwasan_thread.cc105
-rw-r--r--lib/hwasan/hwasan_thread.h62
-rw-r--r--lib/hwasan/hwasan_thread_list.cc15
-rw-r--r--lib/hwasan/hwasan_thread_list.h200
-rw-r--r--lib/interception/interception.h3
-rw-r--r--lib/interception/interception_linux.h2
-rw-r--r--lib/interception/interception_win.cc8
-rw-r--r--lib/lsan/lsan_allocator.cc3
-rw-r--r--lib/lsan/lsan_allocator.h36
-rw-r--r--lib/lsan/lsan_common.cc9
-rw-r--r--lib/lsan/lsan_common_mac.cc12
-rw-r--r--lib/lsan/lsan_interceptors.cc2
-rw-r--r--lib/msan/msan.cc6
-rw-r--r--lib/msan/msan_allocator.cc8
-rw-r--r--lib/msan/msan_interceptors.cc76
-rw-r--r--lib/msan/msan_linux.cc46
-rw-r--r--lib/msan/tests/msan_test.cc4
-rw-r--r--lib/profile/GCDAProfiling.c49
-rw-r--r--lib/profile/InstrProfData.inc20
-rw-r--r--lib/profile/InstrProfilingPlatformLinux.c2
-rw-r--r--lib/profile/InstrProfilingPlatformOther.c2
-rw-r--r--lib/profile/InstrProfilingValue.c5
-rw-r--r--lib/profile/WindowsMMap.c8
-rw-r--r--lib/profile/WindowsMMap.h10
-rw-r--r--lib/safestack/CMakeLists.txt27
-rw-r--r--lib/safestack/safestack.cc83
-rw-r--r--lib/sanitizer_common/CMakeLists.txt12
-rw-r--r--lib/sanitizer_common/sanitizer_allocator.h6
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_bytemap.h11
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_combined.h16
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_internal.h3
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_primary32.h5
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_primary64.h5
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_secondary.h19
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_size_class_map.h8
-rw-r--r--lib/sanitizer_common/sanitizer_atomic_clang_x86.h6
-rw-r--r--lib/sanitizer_common/sanitizer_common.cc5
-rw-r--r--lib/sanitizer_common/sanitizer_common.h14
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors.inc2340
-rw-r--r--lib/sanitizer_common/sanitizer_common_libcdep.cc21
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_fuchsia.cc9
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_win_sections.cc53
-rw-r--r--lib/sanitizer_common/sanitizer_file.h3
-rw-r--r--lib/sanitizer_common/sanitizer_flags.inc5
-rw-r--r--lib/sanitizer_common/sanitizer_fuchsia.cc69
-rw-r--r--lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc55
-rw-r--r--lib/sanitizer_common/sanitizer_internal_defs.h10
-rw-r--r--lib/sanitizer_common/sanitizer_libc.cc12
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc304
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h13
-rw-r--r--lib/sanitizer_common/sanitizer_linux_libcdep.cc45
-rw-r--r--lib/sanitizer_common/sanitizer_local_address_space_view.h77
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc109
-rw-r--r--lib/sanitizer_common/sanitizer_mac.h5
-rw-r--r--lib/sanitizer_common/sanitizer_malloc_mac.inc37
-rw-r--r--lib/sanitizer_common/sanitizer_netbsd.cc335
-rw-r--r--lib/sanitizer_common/sanitizer_openbsd.cc29
-rw-r--r--lib/sanitizer_common/sanitizer_platform.h22
-rw-r--r--lib/sanitizer_common/sanitizer_platform_interceptors.h49
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_freebsd.cc526
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_freebsd.h657
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc358
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_netbsd.h175
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.cc94
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.h139
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_solaris.h3
-rw-r--r--lib/sanitizer_common/sanitizer_posix.cc40
-rw-r--r--lib/sanitizer_common/sanitizer_posix.h12
-rw-r--r--lib/sanitizer_common/sanitizer_posix_libcdep.cc8
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps.h1
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_bsd.cc9
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_common.cc6
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_linux.cc1
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_mac.cc12
-rw-r--r--lib/sanitizer_common/sanitizer_procmaps_solaris.cc11
-rw-r--r--lib/sanitizer_common/sanitizer_ring_buffer.h162
-rw-r--r--lib/sanitizer_common/sanitizer_rtems.cc8
-rw-r--r--lib/sanitizer_common/sanitizer_solaris.cc49
-rw-r--r--lib/sanitizer_common/sanitizer_stackdepot.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_stackdepot.h2
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.h2
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc24
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_printer.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_sparc.cc5
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h3
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_generic.inc39
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc3
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_linux_arm.inc3
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc3
-rw-r--r--lib/sanitizer_common/sanitizer_syscalls_netbsd.inc38
-rw-r--r--lib/sanitizer_common/sanitizer_termination.cc9
-rw-r--r--lib/sanitizer_common/sanitizer_thread_registry.cc11
-rw-r--r--lib/sanitizer_common/sanitizer_thread_registry.h1
-rw-r--r--lib/sanitizer_common/sanitizer_type_traits.cc21
-rw-r--r--lib/sanitizer_common/sanitizer_type_traits.h44
-rw-r--r--lib/sanitizer_common/sanitizer_unwind_linux_libcdep.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc21
-rw-r--r--lib/sanitizer_common/sanitizer_win_defs.h20
-rwxr-xr-xlib/sanitizer_common/scripts/gen_dynamic_list.py23
-rw-r--r--lib/sanitizer_common/symbolizer/scripts/global_symbols.txt3
-rw-r--r--lib/sanitizer_common/tests/CMakeLists.txt9
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator_test.cc109
-rw-r--r--lib/sanitizer_common/tests/sanitizer_common_test.cc3
-rw-r--r--lib/sanitizer_common/tests/sanitizer_ring_buffer_test.cc99
-rw-r--r--lib/sanitizer_common/tests/sanitizer_type_traits_test.cc28
-rw-r--r--lib/scudo/CMakeLists.txt8
-rw-r--r--lib/scudo/scudo_allocator.cpp27
-rw-r--r--lib/scudo/scudo_allocator.h4
-rw-r--r--lib/scudo/scudo_malloc.cpp2
-rw-r--r--lib/tsan/CMakeLists.txt20
-rwxr-xr-xlib/tsan/check_analyze.sh14
-rwxr-xr-xlib/tsan/go/buildgo.sh14
-rw-r--r--lib/tsan/rtl/tsan_debugging.cc50
-rw-r--r--lib/tsan/rtl/tsan_flags.cc3
-rw-r--r--lib/tsan/rtl/tsan_flags.inc2
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc75
-rw-r--r--lib/tsan/rtl/tsan_interceptors.h4
-rw-r--r--lib/tsan/rtl/tsan_interceptors_mac.cc65
-rw-r--r--lib/tsan/rtl/tsan_libdispatch_mac.cc5
-rw-r--r--lib/tsan/rtl/tsan_platform.h44
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc8
-rw-r--r--lib/tsan/rtl/tsan_platform_mac.cc8
-rw-r--r--lib/tsan/rtl/tsan_report.cc67
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc4
-rw-r--r--lib/tsan/rtl/tsan_rtl.h9
-rw-r--r--lib/tsan/rtl/tsan_rtl_aarch64.S12
-rw-r--r--lib/tsan/rtl/tsan_rtl_amd64.S3
-rw-r--r--lib/tsan/rtl/tsan_rtl_thread.cc6
-rw-r--r--lib/tsan/rtl/tsan_suppressions.cc56
-rw-r--r--lib/ubsan/ubsan_checks.inc15
-rw-r--r--lib/ubsan/ubsan_flags.inc4
-rw-r--r--lib/ubsan/ubsan_handlers.cc97
-rw-r--r--lib/ubsan/ubsan_handlers.h17
-rw-r--r--lib/ubsan/ubsan_interface.inc2
-rw-r--r--lib/ubsan_minimal/CMakeLists.txt8
-rw-r--r--lib/ubsan_minimal/ubsan_minimal_handlers.cc1
-rw-r--r--lib/xray/CMakeLists.txt6
-rw-r--r--lib/xray/tests/CMakeLists.txt47
-rw-r--r--lib/xray/tests/unit/CMakeLists.txt28
-rw-r--r--lib/xray/tests/unit/allocator_test.cc42
-rw-r--r--lib/xray/tests/unit/buffer_queue_test.cc129
-rw-r--r--lib/xray/tests/unit/fdr_controller_test.cc424
-rw-r--r--lib/xray/tests/unit/fdr_log_writer_test.cc162
-rw-r--r--lib/xray/tests/unit/fdr_logging_test.cc202
-rw-r--r--lib/xray/tests/unit/function_call_trie_test.cc168
-rw-r--r--lib/xray/tests/unit/profile_collector_test.cc65
-rw-r--r--lib/xray/tests/unit/segmented_array_test.cc149
-rw-r--r--lib/xray/tests/unit/test_helpers.cc95
-rw-r--r--lib/xray/tests/unit/test_helpers.h78
-rw-r--r--lib/xray/xray_allocator.h210
-rw-r--r--lib/xray/xray_basic_logging.cc145
-rw-r--r--lib/xray/xray_buffer_queue.cc281
-rw-r--r--lib/xray/xray_buffer_queue.h81
-rw-r--r--lib/xray/xray_defs.h10
-rw-r--r--lib/xray/xray_fdr_controller.h373
-rw-r--r--lib/xray/xray_fdr_log_records.h5
-rw-r--r--lib/xray/xray_fdr_log_writer.h232
-rw-r--r--lib/xray/xray_fdr_logging.cc1096
-rw-r--r--lib/xray/xray_function_call_trie.h387
-rw-r--r--lib/xray/xray_init.cc18
-rw-r--r--lib/xray/xray_interface.cc41
-rw-r--r--lib/xray/xray_profile_collector.cc361
-rw-r--r--lib/xray/xray_profile_collector.h26
-rw-r--r--lib/xray/xray_profiling.cc387
-rw-r--r--lib/xray/xray_profiling_flags.inc5
-rw-r--r--lib/xray/xray_segmented_array.h584
-rw-r--r--lib/xray/xray_trampoline_x86_64.S4
-rw-r--r--lib/xray/xray_tsc.h23
-rw-r--r--lib/xray/xray_utils.cc172
-rw-r--r--lib/xray/xray_utils.h47
-rw-r--r--lib/xray/xray_x86_64.cc22
-rw-r--r--test/.clang-format2
-rw-r--r--test/CMakeLists.txt2
-rw-r--r--test/asan/CMakeLists.txt2
-rw-r--r--test/asan/TestCases/Darwin/init_for_dlopen.cc46
-rw-r--r--test/asan/TestCases/Darwin/odr-lto.cc4
-rw-r--r--test/asan/TestCases/Darwin/segv_read_write.c5
-rw-r--r--test/asan/TestCases/Linux/asan_rt_confict_test-2.cc4
-rw-r--r--test/asan/TestCases/Linux/coverage-missing.cc10
-rw-r--r--test/asan/TestCases/Linux/local_alias.cc11
-rw-r--r--test/asan/TestCases/Linux/new_delete_mismatch.cc1
-rw-r--r--test/asan/TestCases/Linux/new_delete_mismatch_global.cc16
-rw-r--r--test/asan/TestCases/Linux/new_delete_mismatch_stack.cc17
-rw-r--r--test/asan/TestCases/Linux/odr-violation.cc26
-rw-r--r--test/asan/TestCases/Linux/odr-vtable.cc26
-rw-r--r--test/asan/TestCases/Linux/odr_c_test.c8
-rw-r--r--test/asan/TestCases/Linux/odr_indicators.cc26
-rw-r--r--test/asan/TestCases/Linux/preinit_test.cc7
-rw-r--r--test/asan/TestCases/Linux/preinstalled_signal.cc2
-rw-r--r--test/asan/TestCases/Posix/coverage-reset.cc2
-rw-r--r--test/asan/TestCases/Posix/coverage.cc1
-rw-r--r--test/asan/TestCases/Posix/dlclose-test.cc2
-rw-r--r--test/asan/TestCases/Posix/interception-in-shared-lib-test.cc2
-rw-r--r--test/asan/TestCases/Posix/mmap_limit_mb.cc2
-rw-r--r--test/asan/TestCases/Posix/no-fd.cc43
-rw-r--r--test/asan/TestCases/Posix/stack-use-after-return.cc4
-rw-r--r--test/asan/TestCases/Posix/strndup_oob_test.cc2
-rw-r--r--test/asan/TestCases/Posix/strndup_oob_test2.cc44
-rw-r--r--test/asan/TestCases/Posix/tsd_dtor_leak.cc3
-rw-r--r--test/asan/TestCases/asan_and_llvm_coverage_test.cc3
-rw-r--r--test/asan/TestCases/atoll_strict.c2
-rw-r--r--test/asan/TestCases/heavy_uar_test.cc6
-rw-r--r--test/asan/TestCases/initialization-bug.cc2
-rw-r--r--test/asan/TestCases/intercept-rethrow-exception.cc4
-rw-r--r--test/asan/TestCases/interception_failure_test.cc4
-rw-r--r--test/asan/TestCases/intra-object-overflow.cc2
-rw-r--r--test/asan/TestCases/log-path_test.cc2
-rw-r--r--test/asan/TestCases/pass-object-byval.cc2
-rw-r--r--test/asan/TestCases/printf-2.c2
-rw-r--r--test/asan/TestCases/printf-3.c6
-rw-r--r--test/asan/TestCases/printf-4.c2
-rw-r--r--test/asan/TestCases/printf-5.c2
-rw-r--r--test/asan/TestCases/printf-m.c2
-rw-r--r--test/asan/TestCases/set_shadow_test.c2
-rw-r--r--test/asan/TestCases/strcasestr-1.c2
-rw-r--r--test/asan/TestCases/strcasestr-2.c2
-rw-r--r--test/asan/TestCases/strcasestr_strict.c2
-rw-r--r--test/asan/TestCases/strcat-overlap.cc2
-rw-r--r--test/asan/TestCases/strncasecmp_strict.c2
-rw-r--r--test/asan/TestCases/strtoll_strict.c2
-rw-r--r--test/asan/TestCases/suppressions-exec-relative-location.cc2
-rw-r--r--test/asan/TestCases/suppressions-function.cc2
-rw-r--r--test/asan/TestCases/suppressions-library.cc1
-rw-r--r--test/asan/TestCases/throw_catch.cc2
-rw-r--r--test/asan/TestCases/time_interceptor.cc2
-rw-r--r--test/asan/TestCases/verbose-log-path_test.cc2
-rw-r--r--test/asan/lit.cfg11
-rw-r--r--test/builtins/CMakeLists.txt10
-rw-r--r--test/builtins/Unit/absvti2_test.c1
-rw-r--r--test/builtins/Unit/addvti3_test.c1
-rw-r--r--test/builtins/Unit/ashlti3_test.c1
-rw-r--r--test/builtins/Unit/ashrti3_test.c1
-rw-r--r--test/builtins/Unit/clzti2_test.c1
-rw-r--r--test/builtins/Unit/cmpti2_test.c1
-rw-r--r--test/builtins/Unit/compiler_rt_logb_test.c63
-rw-r--r--test/builtins/Unit/compiler_rt_logbf_test.c63
-rw-r--r--test/builtins/Unit/compiler_rt_logbl_test.c79
-rw-r--r--test/builtins/Unit/ctzti2_test.c1
-rw-r--r--test/builtins/Unit/divti3_test.c1
-rw-r--r--test/builtins/Unit/ffsti2_test.c1
-rw-r--r--test/builtins/Unit/fixdfti_test.c1
-rw-r--r--test/builtins/Unit/fixsfti_test.c1
-rw-r--r--test/builtins/Unit/fixunsdfti_test.c21
-rw-r--r--test/builtins/Unit/fixunssfti_test.c9
-rw-r--r--test/builtins/Unit/fixunsxfti_test.c4
-rw-r--r--test/builtins/Unit/fixxfdi_test.c2
-rw-r--r--test/builtins/Unit/fixxfti_test.c10
-rw-r--r--test/builtins/Unit/floattidf_test.c1
-rw-r--r--test/builtins/Unit/floattisf_test.c1
-rw-r--r--test/builtins/Unit/floattixf_test.c10
-rw-r--r--test/builtins/Unit/floatuntidf_test.c1
-rw-r--r--test/builtins/Unit/floatuntisf_test.c10
-rw-r--r--test/builtins/Unit/floatuntixf_test.c10
-rw-r--r--test/builtins/Unit/lit.cfg8
-rw-r--r--test/builtins/Unit/lit.site.cfg.in3
-rw-r--r--test/builtins/Unit/lshrti3_test.c1
-rw-r--r--test/builtins/Unit/modti3_test.c13
-rw-r--r--test/builtins/Unit/muloti4_test.c1
-rw-r--r--test/builtins/Unit/multi3_test.c1
-rw-r--r--test/builtins/Unit/mulvti3_test.c7
-rw-r--r--test/builtins/Unit/negti2_test.c1
-rw-r--r--test/builtins/Unit/negvti2_test.c1
-rw-r--r--test/builtins/Unit/parityti2_test.c1
-rw-r--r--test/builtins/Unit/popcountti2_test.c1
-rw-r--r--test/builtins/Unit/ppc/fixtfdi_test.c6
-rw-r--r--test/builtins/Unit/ppc/fixunstfti_test.c52
-rw-r--r--test/builtins/Unit/ppc/fixunstfti_test.h706
-rw-r--r--test/builtins/Unit/ppc/floatditf_test.c5
-rw-r--r--test/builtins/Unit/ppc/floattitf_test.c59
-rw-r--r--test/builtins/Unit/ppc/floattitf_test.h197
-rw-r--r--test/builtins/Unit/ppc/floatunditf_test.c5
-rw-r--r--test/builtins/Unit/ppc/qadd_test.c4
-rw-r--r--test/builtins/Unit/ppc/qdiv_test.c4
-rw-r--r--test/builtins/Unit/ppc/qmul_test.c4
-rw-r--r--test/builtins/Unit/ppc/qsub_test.c4
-rw-r--r--test/builtins/Unit/subvti3_test.c1
-rw-r--r--test/builtins/Unit/ucmpti2_test.c1
-rw-r--r--test/builtins/Unit/udivmodti4_test.c1
-rw-r--r--test/builtins/Unit/udivti3_test.c1
-rw-r--r--test/builtins/Unit/umodti3_test.c1
-rw-r--r--test/cfi/bad-split.cpp2
-rw-r--r--test/cfi/cross-dso-diagnostic.cpp2
-rw-r--r--test/cfi/cross-dso/lit.local.cfg2
-rw-r--r--test/cfi/mfcall.cpp2
-rw-r--r--test/cfi/target_uninstrumented.cpp2
-rw-r--r--test/cfi/two-vcalls.cpp2
-rw-r--r--test/esan/TestCases/large-stack-linux.c2
-rw-r--r--test/esan/TestCases/workingset-early-fault.c2
-rw-r--r--test/esan/TestCases/workingset-memset.cpp2
-rw-r--r--test/esan/TestCases/workingset-midreport.cpp2
-rw-r--r--test/esan/TestCases/workingset-samples.cpp2
-rw-r--r--test/esan/TestCases/workingset-signal-posix.cpp2
-rw-r--r--test/esan/TestCases/workingset-simple.cpp2
-rw-r--r--test/esan/lit.cfg3
-rw-r--r--test/fuzzer/AlignmentAssumptionTest.cpp27
-rw-r--r--test/fuzzer/ImplicitIntegerSignChangeTest.cpp27
-rw-r--r--test/fuzzer/ImplicitSignedIntegerTruncationOrSignChangeTest.cpp27
-rw-r--r--test/fuzzer/ImplicitSignedIntegerTruncationTest.cpp (renamed from test/fuzzer/ImplicitIntegerTruncationTest.cpp)4
-rw-r--r--test/fuzzer/ImplicitUnsignedIntegerTruncationTest.cpp27
-rw-r--r--test/fuzzer/InitializeTest.cpp5
-rw-r--r--test/fuzzer/PrintUnstableStatsTest.cpp69
-rw-r--r--test/fuzzer/ReadBinaryTest.cpp18
-rw-r--r--test/fuzzer/SymbolizeDeadlock.cpp1
-rw-r--r--test/fuzzer/afl-driver-extra-stats.test2
-rw-r--r--test/fuzzer/afl-driver-stderr.test3
-rw-r--r--test/fuzzer/counters.test3
-rw-r--r--test/fuzzer/coverage.test3
-rw-r--r--test/fuzzer/dead-stripping.test23
-rw-r--r--test/fuzzer/dso.test2
-rw-r--r--test/fuzzer/dump_coverage.test5
-rw-r--r--test/fuzzer/exit_on_src_pos.test10
-rw-r--r--test/fuzzer/fuzzer-alignment-assumption.test7
-rw-r--r--test/fuzzer/fuzzer-implicit-integer-sign-change.test5
-rw-r--r--test/fuzzer/fuzzer-implicit-integer-truncation.test5
-rw-r--r--test/fuzzer/fuzzer-implicit-signed-integer-truncation-or-sign-change.test5
-rw-r--r--test/fuzzer/fuzzer-implicit-signed-integer-truncation.test5
-rw-r--r--test/fuzzer/fuzzer-implicit-unsigned-integer-truncation.test5
-rw-r--r--test/fuzzer/fuzzer-mutationstats.test5
-rw-r--r--test/fuzzer/fuzzer-oom.test22
-rw-r--r--test/fuzzer/gc-sections.test7
-rw-r--r--test/fuzzer/handle-unstable.test42
-rw-r--r--test/fuzzer/lit.cfg21
-rw-r--r--test/fuzzer/merge-control-file.test18
-rw-r--r--test/fuzzer/merge-posix.test1
-rw-r--r--test/fuzzer/merge-sigusr.test4
-rw-r--r--test/fuzzer/minimize_crash.test1
-rw-r--r--test/fuzzer/minimize_two_crashes.test4
-rw-r--r--test/fuzzer/null-deref-on-empty.test1
-rw-r--r--test/fuzzer/null-deref.test1
-rw-r--r--test/fuzzer/only-some-bytes.test2
-rw-r--r--test/fuzzer/print_unstable_stats.test3
-rw-r--r--test/fuzzer/read-binary.test7
-rw-r--r--test/fuzzer/shrink.test2
-rw-r--r--test/fuzzer/sigusr.test4
-rw-r--r--test/fuzzer/trace-malloc-threaded.test3
-rw-r--r--test/fuzzer/trace-malloc-unbalanced.test9
-rw-r--r--test/fuzzer/ulimit.test2
-rw-r--r--test/fuzzer/value-profile-cmp.test2
-rw-r--r--test/fuzzer/value-profile-cmp2.test1
-rw-r--r--test/fuzzer/value-profile-cmp3.test1
-rw-r--r--test/fuzzer/value-profile-cmp4.test2
-rw-r--r--test/fuzzer/value-profile-div.test2
-rw-r--r--test/fuzzer/value-profile-load.test2
-rw-r--r--test/fuzzer/value-profile-mem.test1
-rw-r--r--test/fuzzer/value-profile-set.test1
-rw-r--r--test/fuzzer/value-profile-strcmp.test1
-rw-r--r--test/fuzzer/value-profile-strncmp.test2
-rw-r--r--test/fuzzer/value-profile-switch.test2
-rw-r--r--test/fuzzer/windows-opt-ref.test9
-rw-r--r--test/hwasan/CMakeLists.txt3
-rw-r--r--test/hwasan/TestCases/Posix/system-allocator-fallback.cc54
-rw-r--r--test/hwasan/TestCases/abort-message-android.cc28
-rw-r--r--test/hwasan/TestCases/cfi.cc18
-rw-r--r--test/hwasan/TestCases/deep-recursion.c73
-rw-r--r--test/hwasan/TestCases/double-free.c23
-rw-r--r--test/hwasan/TestCases/heap-buffer-overflow.c60
-rw-r--r--test/hwasan/TestCases/hwasan-print-shadow.cc29
-rw-r--r--test/hwasan/TestCases/longjmp.c26
-rw-r--r--test/hwasan/TestCases/malloc-test.c16
-rw-r--r--test/hwasan/TestCases/malloc_fill.cc22
-rw-r--r--test/hwasan/TestCases/many-threads-uaf.c45
-rw-r--r--test/hwasan/TestCases/mem-intrinsics-zero-size.c10
-rw-r--r--test/hwasan/TestCases/mem-intrinsics.c37
-rw-r--r--test/hwasan/TestCases/new-test.cc18
-rw-r--r--test/hwasan/TestCases/print-memory-usage-android.c21
-rw-r--r--test/hwasan/TestCases/print-memory-usage.c72
-rw-r--r--test/hwasan/TestCases/pthread_exit.c5
-rw-r--r--test/hwasan/TestCases/random-align-right.c35
-rw-r--r--test/hwasan/TestCases/realloc-after-free.c28
-rw-r--r--test/hwasan/TestCases/realloc-test.cc37
-rw-r--r--test/hwasan/TestCases/rich-stack.c66
-rw-r--r--test/hwasan/TestCases/sanitizer_malloc.cc29
-rw-r--r--test/hwasan/TestCases/sizes.cpp80
-rw-r--r--test/hwasan/TestCases/stack-history-length.c36
-rw-r--r--test/hwasan/TestCases/stack-oob.c25
-rw-r--r--test/hwasan/TestCases/stack-oob.cc25
-rw-r--r--test/hwasan/TestCases/stack-uar.c41
-rw-r--r--test/hwasan/TestCases/stack-uar.cc23
-rw-r--r--test/hwasan/TestCases/tail-magic.c28
-rw-r--r--test/hwasan/TestCases/thread-uaf.c58
-rw-r--r--test/hwasan/TestCases/uaf_with_rb_distance.c27
-rw-r--r--test/hwasan/TestCases/use-after-free.c43
-rw-r--r--test/hwasan/lit.cfg6
-rw-r--r--test/hwasan/lit.site.cfg.in1
-rw-r--r--test/lit.common.cfg69
-rw-r--r--test/lit.common.configured.in3
-rw-r--r--test/lsan/TestCases/Linux/fork_and_leak.cc23
-rw-r--r--test/lsan/TestCases/Linux/fork_with_threads.cc35
-rw-r--r--test/lsan/TestCases/Linux/use_tls_dynamic.cc5
-rw-r--r--test/msan/Linux/reexec_unlimited_stack.cc23
-rw-r--r--test/msan/Linux/sunrpc.cc2
-rw-r--r--test/msan/Linux/sunrpc_bytes.cc2
-rw-r--r--test/msan/Linux/sunrpc_string.cc2
-rw-r--r--test/msan/chained_origin_with_signals.cc3
-rw-r--r--test/msan/dtls_test.c8
-rw-r--r--test/msan/fork.cc3
-rw-r--r--test/msan/ioctl_custom.cc3
-rw-r--r--test/msan/lit.cfg8
-rw-r--r--test/msan/pthread_getname_np.cc6
-rw-r--r--test/msan/signal_stress_test.cc3
-rw-r--r--test/msan/strndup.cc2
-rw-r--r--test/msan/tls_reuse.cc1
-rw-r--r--test/msan/vararg.cc60
-rw-r--r--test/profile/Inputs/instrprof-dlopen-dlclose-main.c.gcov2
-rw-r--r--test/profile/Inputs/instrprof-dlopen-dlclose-main_three-libs.c.gcov2
-rw-r--r--test/profile/Inputs/instrprof-gcov-__gcov_flush-multiple.c16
-rw-r--r--test/profile/Inputs/instrprof-gcov-__gcov_flush-multiple.c.gcov21
-rw-r--r--test/profile/Inputs/instrprof-gcov-exceptions.cpp.gcov6
-rw-r--r--test/profile/Inputs/instrprof-gcov-execlp.c15
-rw-r--r--test/profile/Inputs/instrprof-gcov-execlp.c.gcov23
-rw-r--r--test/profile/Inputs/instrprof-gcov-execvp.c17
-rw-r--r--test/profile/Inputs/instrprof-gcov-execvp.c.gcov25
-rw-r--r--test/profile/Inputs/instrprof-gcov-fork.c.gcov4
-rw-r--r--test/profile/Inputs/instrprof-gcov-multiple-bbs-single-line.c.gcov2
-rw-r--r--test/profile/Inputs/instrprof-gcov-one-line-function.c11
-rw-r--r--test/profile/Inputs/instrprof-gcov-one-line-function.c.gcov16
-rw-r--r--test/profile/Inputs/instrprof-gcov-switch1.c.gcov6
-rw-r--r--test/profile/Inputs/instrprof-gcov-switch2.c.gcov6
-rw-r--r--test/profile/Inputs/instrprof-shared-lib.c.gcov2
-rw-r--r--test/profile/Inputs/instrprof-shared-lib_called-twice.c.gcov2
-rw-r--r--test/profile/Inputs/instrprof-shared-lib_in-loop.c.gcov2
-rw-r--r--test/profile/Inputs/instrprof-shared-main-gcov-flush_no-writeout.c.gcov4
-rw-r--r--test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-after.c.gcov4
-rw-r--r--test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-before-after.c.gcov4
-rw-r--r--test/profile/Inputs/instrprof-shared-main-gcov-flush_shared-call-before.c.gcov4
-rw-r--r--test/profile/Inputs/instrprof-shared-main.c.gcov6
-rw-r--r--test/profile/Posix/instrprof-gcov-execlp.test10
-rw-r--r--test/profile/Posix/instrprof-gcov-execvp.test10
-rw-r--r--test/profile/Posix/instrprof-gcov-fork.test2
-rw-r--r--test/profile/instrprof-darwin-exports.c16
-rw-r--r--test/profile/instrprof-dlopen-dlclose-gcov.test7
-rw-r--r--test/profile/instrprof-gcov-__gcov_flush-multiple.test10
-rw-r--r--test/profile/instrprof-gcov-multiple-bbs-single-line.test2
-rw-r--r--test/profile/instrprof-gcov-one-line-function.test9
-rw-r--r--test/profile/instrprof-gcov-two-objects.test2
-rw-r--r--test/profile/instrprof-merging.cpp53
-rw-r--r--test/profile/instrprof-shared-gcov-flush.test8
-rw-r--r--test/profile/lit.cfg2
-rw-r--r--test/safestack/lit.cfg2
-rw-r--r--test/safestack/pthread-cleanup.c41
-rw-r--r--test/safestack/pthread-stack-size.c53
-rw-r--r--test/safestack/pthread.c2
-rw-r--r--test/sanitizer_common/CMakeLists.txt7
-rw-r--r--test/sanitizer_common/TestCases/FreeBSD/capsicum.cc68
-rw-r--r--test/sanitizer_common/TestCases/FreeBSD/fdevname.cc44
-rw-r--r--test/sanitizer_common/TestCases/FreeBSD/lit.local.cfg9
-rw-r--r--test/sanitizer_common/TestCases/Linux/allow_user_segv.cc2
-rw-r--r--test/sanitizer_common/TestCases/Linux/assert.cc2
-rw-r--r--test/sanitizer_common/TestCases/Linux/ill.cc2
-rw-r--r--test/sanitizer_common/TestCases/Linux/mallopt.cc10
-rw-r--r--test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc2
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/asysctl.cc44
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/cdb.cc134
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/fparseln.cc25
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/funopen2.cc110
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/getgroupmembership.cc2
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/getvfsstat.cc36
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/md2.cc114
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/md4.cc114
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/md5.cc114
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/mi_vector_hash.cc19
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/rmd160.cc133
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/sha1.cc171
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/sha2.cc206
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/statvfs1.cc58
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/strtoi.cc43
-rw-r--r--test/sanitizer_common/TestCases/NetBSD/sysctlgetmibinfo.cc36
-rw-r--r--test/sanitizer_common/TestCases/Posix/arc4random.cc71
-rw-r--r--test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc2
-rw-r--r--test/sanitizer_common/TestCases/Posix/devname.cc8
-rw-r--r--test/sanitizer_common/TestCases/Posix/devname_r.cc11
-rw-r--r--test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc2
-rw-r--r--test/sanitizer_common/TestCases/Posix/feof_fileno_ferror.cc41
-rw-r--r--test/sanitizer_common/TestCases/Posix/fgetc_ungetc_getc.cc19
-rw-r--r--test/sanitizer_common/TestCases/Posix/fgetln.cc16
-rw-r--r--test/sanitizer_common/TestCases/Posix/fgets.cc18
-rw-r--r--test/sanitizer_common/TestCases/Posix/fputc_putc_putchar.cc13
-rw-r--r--test/sanitizer_common/TestCases/Posix/fputs_puts.cc12
-rw-r--r--test/sanitizer_common/TestCases/Posix/fseek.cc53
-rw-r--r--test/sanitizer_common/TestCases/Posix/fts.cc42
-rw-r--r--test/sanitizer_common/TestCases/Posix/funopen.cc91
-rw-r--r--test/sanitizer_common/TestCases/Posix/getc_unlocked.cc20
-rw-r--r--test/sanitizer_common/TestCases/Posix/getfsent.cc36
-rw-r--r--test/sanitizer_common/TestCases/Posix/getmntinfo.cc35
-rw-r--r--test/sanitizer_common/TestCases/Posix/getusershell.cc23
-rw-r--r--test/sanitizer_common/TestCases/Posix/lstat.cc8
-rw-r--r--test/sanitizer_common/TestCases/Posix/nl_langinfo.cc20
-rw-r--r--test/sanitizer_common/TestCases/Posix/popen.cc23
-rw-r--r--test/sanitizer_common/TestCases/Posix/putc_putchar_unlocked.cc12
-rw-r--r--test/sanitizer_common/TestCases/Posix/readlinkat.c2
-rw-r--r--test/sanitizer_common/TestCases/Posix/regex.cc71
-rw-r--r--test/sanitizer_common/TestCases/Posix/setvbuf.cc81
-rw-r--r--test/sanitizer_common/TestCases/Posix/sl_add.cc26
-rw-r--r--test/sanitizer_common/TestCases/Posix/strtonum.cc54
-rw-r--r--test/sanitizer_common/TestCases/Posix/sysctl.cc64
-rw-r--r--test/sanitizer_common/TestCases/Posix/vis.cc247
-rw-r--r--test/sanitizer_common/TestCases/allocator_returns_null.cc2
-rw-r--r--test/sanitizer_common/TestCases/corelimit.cc2
-rw-r--r--test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc2
-rw-r--r--test/sanitizer_common/TestCases/hard_rss_limit_mb_test.cc (renamed from test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc)3
-rw-r--r--test/sanitizer_common/TestCases/malloc_hook.cc2
-rw-r--r--test/sanitizer_common/TestCases/pthread_mutexattr_get.cc3
-rw-r--r--test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc2
-rw-r--r--test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc2
-rw-r--r--test/sanitizer_common/TestCases/strcasestr.c2
-rw-r--r--test/sanitizer_common/TestCases/symbolize_pc.cc23
-rw-r--r--test/sanitizer_common/TestCases/symbolize_pc_inline.cc32
-rwxr-xr-xtest/sanitizer_common/ios_commands/iossim_run.py24
-rw-r--r--test/sanitizer_common/lit.common.cfg6
-rw-r--r--test/scudo/dealloc-race.c69
-rw-r--r--test/tsan/Darwin/gcd-sync-block-copy.mm34
-rw-r--r--test/tsan/Darwin/ignore-noninstrumented.mm5
-rw-r--r--test/tsan/Darwin/ignored-interceptors.mm55
-rw-r--r--test/tsan/Darwin/objc-synchronize-cycle-tagged.mm42
-rw-r--r--test/tsan/Darwin/objc-synchronize-cycle.mm31
-rw-r--r--test/tsan/Darwin/objc-synchronize-nested-recursive.mm35
-rw-r--r--test/tsan/Linux/thread_timedjoin.c39
-rw-r--r--test/tsan/Linux/thread_tryjoin.c41
-rw-r--r--test/tsan/cxa_guard_acquire.cc25
-rw-r--r--test/tsan/deadlock_detector_stress_test.cc10
-rw-r--r--test/tsan/dtls.c1
-rw-r--r--test/tsan/getline_nohang.cc3
-rw-r--r--test/tsan/ignore_lib5.cc4
-rw-r--r--test/tsan/ignored-interceptors-mmap.cc63
-rw-r--r--test/tsan/large_malloc_meta.cc3
-rw-r--r--test/tsan/mmap_large.cc3
-rw-r--r--test/tsan/mutex_cycle2.c2
-rw-r--r--test/tsan/mutex_lock_destroyed.cc3
-rw-r--r--test/tsan/strerror_r.cc8
-rw-r--r--test/tsan/sunrpc.cc2
-rw-r--r--test/ubsan/CMakeLists.txt63
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/integer-arithmetic-value-change.c345
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/integer-conversion.c351
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/integer-sign-change-blacklist.c28
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/integer-sign-change-summary.cpp (renamed from test/ubsan/TestCases/ImplicitConversion/integer-truncation-summary.cpp)6
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/integer-sign-change.c297
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/integer-truncation-blacklist.c20
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/integer-truncation.c363
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/signed-integer-truncation-blacklist.c60
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/signed-integer-truncation-or-sign-change-blacklist.c58
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/signed-integer-truncation-or-sign-change-summary.cpp13
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/signed-integer-truncation-summary.cpp13
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/signed-integer-truncation.c318
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/unsigned-integer-truncation-blacklist.c60
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/unsigned-integer-truncation-summary.cpp13
-rw-r--r--test/ubsan/TestCases/ImplicitConversion/unsigned-integer-truncation.c304
-rw-r--r--test/ubsan/TestCases/Integer/no-recover.cpp4
-rw-r--r--test/ubsan/TestCases/Misc/enum.cpp2
-rw-r--r--test/ubsan/TestCases/Misc/log-path_test.cc4
-rw-r--r--test/ubsan/TestCases/Misc/monitor.cpp2
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-attribute-align_value-on-lvalue.cpp36
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-attribute-align_value-on-paramvar.cpp30
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-attribute-alloc_align-on-function-variable.cpp33
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-attribute-alloc_align-on-function.cpp29
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-attribute-assume_aligned-on-function-two-params.cpp28
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-attribute-assume_aligned-on-function.cpp28
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-blacklist.cpp20
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-builtin_assume_aligned-three-params-variable.cpp27
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-builtin_assume_aligned-three-params.cpp23
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-builtin_assume_aligned-two-params.cpp23
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-openmp.cpp28
-rw-r--r--test/ubsan/TestCases/Pointer/alignment-assumption-summary.cpp17
-rw-r--r--test/ubsan/TestCases/Pointer/index-overflow.cpp6
-rw-r--r--test/ubsan/TestCases/Pointer/unsigned-index-expression.cpp2
-rw-r--r--test/ubsan/TestCases/TypeCheck/Function/function.cpp2
-rw-r--r--test/ubsan/TestCases/TypeCheck/PR33221.cpp2
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp2
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr-non-unique-typeinfo.cpp3
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr-virtual-base-construction.cpp2
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp4
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr.cpp4
-rw-r--r--test/ubsan/lit.common.cfg5
-rw-r--r--test/ubsan/lit.site.cfg.in1
-rw-r--r--test/ubsan_minimal/TestCases/alignment-assumption.c17
-rw-r--r--test/ubsan_minimal/TestCases/implicit-integer-sign-change.c17
-rw-r--r--test/ubsan_minimal/TestCases/implicit-signed-integer-truncation-or-sign-change.c17
-rw-r--r--test/ubsan_minimal/TestCases/implicit-signed-integer-truncation.c25
-rw-r--r--test/ubsan_minimal/TestCases/implicit-unsigned-integer-truncation.c (renamed from test/ubsan_minimal/TestCases/implicit-integer-truncation.c)5
-rw-r--r--test/xray/TestCases/Posix/argv0-log-file-name.cc2
-rw-r--r--test/xray/TestCases/Posix/basic-filtering.cc4
-rw-r--r--test/xray/TestCases/Posix/clang-no-xray-instrument.cc11
-rw-r--r--test/xray/TestCases/Posix/fdr-mode.cc33
-rw-r--r--test/xray/TestCases/Posix/fdr-reinit.cc73
-rw-r--r--test/xray/TestCases/Posix/fdr-single-thread.cc12
-rw-r--r--test/xray/TestCases/Posix/fdr-thread-order.cc35
-rw-r--r--test/xray/TestCases/Posix/fork_basic_logging.cc21
-rw-r--r--test/xray/TestCases/Posix/profiling-multi-threaded.cc2
-rw-r--r--test/xray/Unit/lit.site.cfg.in8
-rw-r--r--unittests/lit.common.unit.configured.in1
-rwxr-xr-xutils/generate_netbsd_ioctls.awk154
-rwxr-xr-xutils/generate_netbsd_syscalls.awk12
713 files changed, 23344 insertions, 5691 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 86ca2b3ef74b..aa360a3ef36e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,6 +59,9 @@ if (NOT COMPILER_RT_ASAN_SHADOW_SCALE STREQUAL "")
-D${COMPILER_RT_ASAN_SHADOW_SCALE_DEFINITION})
endif()
+set(COMPILER_RT_HWASAN_WITH_INTERCEPTORS ON CACHE BOOLEAN
+ "Enable libc interceptors in HWASan (testing mode)")
+
set(COMPILER_RT_BAREMETAL_BUILD OFF CACHE BOOLEAN
"Build for a bare-metal target.")
@@ -79,6 +82,61 @@ if (COMPILER_RT_STANDALONE_BUILD)
or specify the PYTHON_EXECUTABLE CMake variable.")
endif()
+ # Ensure that fat libraries are built correctly on Darwin
+ if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ if(NOT CMAKE_LIBTOOL)
+ find_program(CMAKE_XCRUN
+ NAMES
+ xcrun)
+ if(CMAKE_XCRUN)
+ execute_process(COMMAND
+ ${CMAKE_XCRUN} -find libtool
+ OUTPUT_VARIABLE
+ CMAKE_LIBTOOL
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif()
+
+ if(NOT CMAKE_LIBTOOL OR NOT EXISTS CMAKE_LIBTOOL)
+ find_program(CMAKE_LIBTOOL
+ NAMES
+ libtool)
+ endif()
+ endif()
+
+ get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+
+ if(CMAKE_LIBTOOL)
+ set(CMAKE_LIBTOOL ${CMAKE_LIBTOOL} CACHE PATH "libtool executable")
+ message(STATUS "Found libtool - ${CMAKE_LIBTOOL}")
+
+ execute_process(COMMAND
+ ${CMAKE_LIBTOOL} -V
+ OUTPUT_VARIABLE
+ LIBTOOL_V_OUTPUT
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if("${LIBTOOL_V_OUTPUT}" MATCHES ".*cctools-([0-9]+).*")
+ string(REGEX REPLACE ".*cctools-([0-9]+).*" "\\1" LIBTOOL_VERSION ${LIBTOOL_V_OUTPUT})
+ if(NOT LIBTOOL_VERSION VERSION_LESS "862")
+ set(LIBTOOL_NO_WARNING_FLAG "-no_warning_for_no_symbols")
+ endif()
+ endif()
+
+ foreach(lang ${languages})
+ set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "\"${CMAKE_LIBTOOL}\" -static ${LIBTOOL_NO_WARNING_FLAG} -o <TARGET> <LINK_FLAGS> <OBJECTS>")
+ endforeach()
+ endif()
+
+ # Workaround SIP :-(
+ if(DYLD_LIBRARY_PATH)
+ set(dyld_envar "DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}")
+ foreach(lang ${languages})
+ foreach(cmd ${CMAKE_${lang}_CREATE_STATIC_LIBRARY})
+ list(APPEND CMAKE_${lang}_CREATE_STATIC_LIBRARY_NEW "${dyld_envar} ${cmd}")
+ endforeach()
+ endforeach()
+ endif()
+ endif()
+
# Define default arguments to lit.
set(LIT_ARGS_DEFAULT "-sv")
if (MSVC OR XCODE)
@@ -89,12 +147,12 @@ if (COMPILER_RT_STANDALONE_BUILD)
endif()
construct_compiler_rt_default_triple()
-if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" MATCHES "hf$")
+if ("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" MATCHES ".*hf$")
if (${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "^arm")
set(COMPILER_RT_DEFAULT_TARGET_ARCH "armhf")
endif()
endif()
-if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" MATCHES "^android")
+if ("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" MATCHES ".*android.*")
set(ANDROID 1)
endif()
pythonize_bool(ANDROID)
@@ -142,7 +200,7 @@ set(CXXABIS none default libstdc++ libc++)
set_property(CACHE SANITIZER_CXX_ABI PROPERTY STRINGS ;${CXXABIS})
if (SANITIZER_CXX_ABI STREQUAL "default")
- if (APPLE)
+ if (APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
set(SANITIZER_CXX_ABI_LIBNAME "libc++")
set(SANITIZER_CXX_ABI_SYSTEM 1)
elseif (FUCHSIA)
@@ -310,11 +368,14 @@ append_list_if(COMPILER_RT_HAS_WD4391_FLAG /wd4391 SANITIZER_COMMON_CFLAGS)
append_list_if(COMPILER_RT_HAS_WD4722_FLAG /wd4722 SANITIZER_COMMON_CFLAGS)
append_list_if(COMPILER_RT_HAS_WD4800_FLAG /wd4800 SANITIZER_COMMON_CFLAGS)
+append_list_if(MINGW -fms-extensions SANITIZER_COMMON_CFLAGS)
+
# Set common link flags.
append_list_if(COMPILER_RT_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs SANITIZER_COMMON_LINK_FLAGS)
if (COMPILER_RT_USE_BUILTINS_LIBRARY)
list(APPEND SANITIZER_COMMON_LINK_LIBS ${COMPILER_RT_BUILTINS_LIBRARY})
+ string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
else()
if (ANDROID)
append_list_if(COMPILER_RT_HAS_GCC_LIB gcc SANITIZER_COMMON_LINK_LIBS)
@@ -325,14 +386,6 @@ endif()
append_list_if(COMPILER_RT_HAS_LIBC c SANITIZER_COMMON_LINK_LIBS)
-if(ANDROID)
-# Put the Sanitizer shared libraries in the global group. For more details, see
-# android-changes-for-ndk-developers.md#changes-to-library-search-order
- if (COMPILER_RT_HAS_Z_GLOBAL)
- list(APPEND SANITIZER_COMMON_LINK_FLAGS -Wl,-z,global)
- endif()
-endif()
-
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia")
list(APPEND SANITIZER_COMMON_LINK_FLAGS -Wl,-z,defs,-z,now,-z,relro)
list(APPEND SANITIZER_COMMON_LINK_LIBS zircon)
@@ -375,15 +428,19 @@ endif()
add_subdirectory(include)
-foreach(path IN ITEMS ${LLVM_MAIN_SRC_DIR}/projects/libcxx
- ${LLVM_MAIN_SRC_DIR}/runtimes/libcxx
- ${LLVM_MAIN_SRC_DIR}/../libcxx
- ${LLVM_EXTERNAL_LIBCXX_SOURCE_DIR})
- if(IS_DIRECTORY ${path})
- set(COMPILER_RT_LIBCXX_PATH ${path})
- break()
- endif()
-endforeach()
+option(COMPILER_RT_USE_LIBCXX
+ "Enable compiler-rt to use libc++ from the source tree" ON)
+if(COMPILER_RT_USE_LIBCXX)
+ foreach(path IN ITEMS ${LLVM_MAIN_SRC_DIR}/projects/libcxx
+ ${LLVM_MAIN_SRC_DIR}/runtimes/libcxx
+ ${LLVM_MAIN_SRC_DIR}/../libcxx
+ ${LLVM_EXTERNAL_LIBCXX_SOURCE_DIR})
+ if(IS_DIRECTORY ${path})
+ set(COMPILER_RT_LIBCXX_PATH ${path})
+ break()
+ endif()
+ endforeach()
+endif()
set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld)
if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD)
diff --git a/LICENSE.TXT b/LICENSE.TXT
index 0134694e4e5f..1c94ad5d8911 100644
--- a/LICENSE.TXT
+++ b/LICENSE.TXT
@@ -14,7 +14,7 @@ Full text of the relevant licenses is included below.
University of Illinois/NCSA
Open Source License
-Copyright (c) 2009-2018 by the contributors listed in CREDITS.TXT
+Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
All rights reserved.
diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake
index cd4c704fc824..81b110203c27 100644
--- a/cmake/Modules/AddCompilerRT.cmake
+++ b/cmake/Modules/AddCompilerRT.cmake
@@ -77,7 +77,7 @@ function(add_compiler_rt_object_libraries name)
endif()
set_target_compile_flags(${libname}
- ${CMAKE_CXX_FLAGS} ${extra_cflags_${libname}} ${target_flags})
+ ${extra_cflags_${libname}} ${target_flags})
set_property(TARGET ${libname} APPEND PROPERTY
COMPILE_DEFINITIONS ${LIB_DEFS})
set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Libraries")
@@ -357,19 +357,20 @@ set(COMPILER_RT_GTEST_CFLAGS
-I${COMPILER_RT_GTEST_PATH}
)
+# Mocking support.
+set(COMPILER_RT_GMOCK_PATH ${LLVM_MAIN_SRC_DIR}/utils/unittest/googlemock)
+set(COMPILER_RT_GMOCK_SOURCE ${COMPILER_RT_GMOCK_PATH}/src/gmock-all.cc)
+set(COMPILER_RT_GMOCK_CFLAGS
+ -DGTEST_NO_LLVM_RAW_OSTREAM=1
+ -DGTEST_HAS_RTTI=0
+ -I${COMPILER_RT_GMOCK_PATH}/include
+ -I${COMPILER_RT_GMOCK_PATH}
+)
+
append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 COMPILER_RT_UNITTEST_CFLAGS)
append_list_if(COMPILER_RT_HAS_WCOVERED_SWITCH_DEFAULT_FLAG -Wno-covered-switch-default COMPILER_RT_UNITTEST_CFLAGS)
if(MSVC)
- # clang doesn't support exceptions on Windows yet.
- list(APPEND COMPILER_RT_UNITTEST_CFLAGS -D_HAS_EXCEPTIONS=0)
-
- # We should teach clang to understand "#pragma intrinsic", see PR19898.
- list(APPEND COMPILER_RT_UNITTEST_CFLAGS -Wno-undefined-inline)
-
- # Clang doesn't support SEH on Windows yet.
- list(APPEND COMPILER_RT_GTEST_CFLAGS -DGTEST_HAS_SEH=0)
-
# gtest use a lot of stuff marked as deprecated on Windows.
list(APPEND COMPILER_RT_GTEST_CFLAGS -Wno-deprecated-declarations)
endif()
@@ -550,6 +551,9 @@ macro(add_custom_libcxx name prefix)
set(PASSTHROUGH_VARIABLES
CMAKE_C_COMPILER_TARGET
CMAKE_CXX_COMPILER_TARGET
+ CMAKE_SHARED_LINKER_FLAGS
+ CMAKE_MODULE_LINKER_FLAGS
+ CMAKE_EXE_LINKER_FLAGS
CMAKE_INSTALL_PREFIX
CMAKE_MAKE_PROGRAM
CMAKE_LINKER
@@ -562,14 +566,20 @@ macro(add_custom_libcxx name prefix)
CMAKE_SYSROOT
CMAKE_SYSTEM_NAME)
foreach(variable ${PASSTHROUGH_VARIABLES})
- if(${variable})
- list(APPEND CMAKE_PASSTHROUGH_VARIABLES -D${variable}=${${variable}})
+ get_property(is_value_set CACHE ${variable} PROPERTY VALUE SET)
+ if(${is_value_set})
+ get_property(value CACHE ${variable} PROPERTY VALUE)
+ list(APPEND CMAKE_PASSTHROUGH_VARIABLES -D${variable}=${value})
endif()
endforeach()
- string(REPLACE ";" " " FLAGS_STRING "${LIBCXX_CFLAGS}")
- set(LIBCXX_C_FLAGS "${FLAGS_STRING}")
- set(LIBCXX_CXX_FLAGS "${FLAGS_STRING}")
+ string(REPLACE ";" " " LIBCXX_C_FLAGS "${LIBCXX_CFLAGS}")
+ get_property(C_FLAGS CACHE CMAKE_C_FLAGS PROPERTY VALUE)
+ set(LIBCXX_C_FLAGS "${LIBCXX_C_FLAGS} ${C_FLAGS}")
+
+ string(REPLACE ";" " " LIBCXX_CXX_FLAGS "${LIBCXX_CFLAGS}")
+ get_property(CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
+ set(LIBCXX_CXX_FLAGS "${LIBCXX_CXX_FLAGS} ${CXX_FLAGS}")
ExternalProject_Add(${name}
DEPENDS ${name}-clobber ${LIBCXX_DEPS}
diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake
index e5651718fa34..5348f2064b67 100644
--- a/cmake/Modules/CompilerRTUtils.cmake
+++ b/cmake/Modules/CompilerRTUtils.cmake
@@ -58,14 +58,6 @@ macro(append_rtti_flag polarity list)
endif()
endmacro()
-macro(append_have_file_definition filename varname list)
- check_include_file("${filename}" "${varname}")
- if (NOT ${varname})
- set("${varname}" 0)
- endif()
- list(APPEND ${list} "${varname}=${${varname}}")
-endmacro()
-
macro(list_intersect output input1 input2)
set(${output})
foreach(it ${${input1}})
@@ -210,47 +202,91 @@ macro(load_llvm_config)
find_program(LLVM_CONFIG_PATH "llvm-config"
DOC "Path to llvm-config binary")
if (NOT LLVM_CONFIG_PATH)
- message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH")
+ message(WARNING "UNSUPPORTED COMPILER-RT CONFIGURATION DETECTED: "
+ "llvm-config not found.\n"
+ "Reconfigure with -DLLVM_CONFIG_PATH=path/to/llvm-config.")
endif()
endif()
- execute_process(
- COMMAND ${LLVM_CONFIG_PATH} "--obj-root" "--bindir" "--libdir" "--src-root"
- RESULT_VARIABLE HAD_ERROR
- OUTPUT_VARIABLE CONFIG_OUTPUT)
- if (HAD_ERROR)
- message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
- endif()
- string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" CONFIG_OUTPUT ${CONFIG_OUTPUT})
- list(GET CONFIG_OUTPUT 0 BINARY_DIR)
- list(GET CONFIG_OUTPUT 1 TOOLS_BINARY_DIR)
- list(GET CONFIG_OUTPUT 2 LIBRARY_DIR)
- list(GET CONFIG_OUTPUT 3 MAIN_SRC_DIR)
+ if (LLVM_CONFIG_PATH)
+ execute_process(
+ COMMAND ${LLVM_CONFIG_PATH} "--obj-root" "--bindir" "--libdir" "--src-root" "--includedir"
+ RESULT_VARIABLE HAD_ERROR
+ OUTPUT_VARIABLE CONFIG_OUTPUT)
+ if (HAD_ERROR)
+ message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
+ endif()
+ string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" CONFIG_OUTPUT ${CONFIG_OUTPUT})
+ list(GET CONFIG_OUTPUT 0 BINARY_DIR)
+ list(GET CONFIG_OUTPUT 1 TOOLS_BINARY_DIR)
+ list(GET CONFIG_OUTPUT 2 LIBRARY_DIR)
+ list(GET CONFIG_OUTPUT 3 MAIN_SRC_DIR)
+ list(GET CONFIG_OUTPUT 4 INCLUDE_DIR)
- set(LLVM_BINARY_DIR ${BINARY_DIR} CACHE PATH "Path to LLVM build tree")
- set(LLVM_TOOLS_BINARY_DIR ${TOOLS_BINARY_DIR} CACHE PATH "Path to llvm/bin")
- set(LLVM_LIBRARY_DIR ${LIBRARY_DIR} CACHE PATH "Path to llvm/lib")
- set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
+ set(LLVM_BINARY_DIR ${BINARY_DIR} CACHE PATH "Path to LLVM build tree")
+ set(LLVM_LIBRARY_DIR ${LIBRARY_DIR} CACHE PATH "Path to llvm/lib")
+ set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
+ set(LLVM_TOOLS_BINARY_DIR ${TOOLS_BINARY_DIR} CACHE PATH "Path to llvm/bin")
+ set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Paths to LLVM headers")
- # Make use of LLVM CMake modules.
- # --cmakedir is supported since llvm r291218 (4.0 release)
- execute_process(
- COMMAND ${LLVM_CONFIG_PATH} --cmakedir
- RESULT_VARIABLE HAD_ERROR
- OUTPUT_VARIABLE CONFIG_OUTPUT)
- if(NOT HAD_ERROR)
- string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH_FROM_LLVM_CONFIG)
- file(TO_CMAKE_PATH ${LLVM_CMAKE_PATH_FROM_LLVM_CONFIG} LLVM_CMAKE_PATH)
- else()
- file(TO_CMAKE_PATH ${LLVM_BINARY_DIR} LLVM_BINARY_DIR_CMAKE_STYLE)
- set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm")
- endif()
+ # Detect if we have the LLVMXRay and TestingSupport library installed and
+ # available from llvm-config.
+ execute_process(
+ COMMAND ${LLVM_CONFIG_PATH} "--ldflags" "--libs" "xray"
+ RESULT_VARIABLE HAD_ERROR
+ OUTPUT_VARIABLE CONFIG_OUTPUT)
+ if (HAD_ERROR)
+ message(WARNING "llvm-config finding xray failed with status ${HAD_ERROR}")
+ set(COMPILER_RT_HAS_LLVMXRAY FALSE)
+ else()
+ string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" CONFIG_OUTPUT ${CONFIG_OUTPUT})
+ list(GET CONFIG_OUTPUT 0 LDFLAGS)
+ list(GET CONFIG_OUTPUT 1 LIBLIST)
+ set(LLVM_XRAY_LDFLAGS ${LDFLAGS} CACHE STRING "Linker flags for LLVMXRay library")
+ set(LLVM_XRAY_LIBLIST ${LIBLIST} CACHE STRING "Library list for LLVMXRay")
+ set(COMPILER_RT_HAS_LLVMXRAY TRUE)
+ endif()
+
+ set(COMPILER_RT_HAS_LLVMTESTINGSUPPORT FALSE)
+ execute_process(
+ COMMAND ${LLVM_CONFIG_PATH} "--ldflags" "--libs" "testingsupport"
+ RESULT_VARIABLE HAD_ERROR
+ OUTPUT_VARIABLE CONFIG_OUTPUT)
+ if (HAD_ERROR)
+ message(WARNING "llvm-config finding testingsupport failed with status ${HAD_ERROR}")
+ else()
+ string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" CONFIG_OUTPUT ${CONFIG_OUTPUT})
+ list(GET CONFIG_OUTPUT 0 LDFLAGS)
+ list(GET CONFIG_OUTPUT 1 LIBLIST)
+ if (LIBLIST STREQUAL "")
+ message(WARNING "testingsupport library not installed, some tests will be skipped")
+ else()
+ set(LLVM_TESTINGSUPPORT_LDFLAGS ${LDFLAGS} CACHE STRING "Linker flags for LLVMTestingSupport library")
+ set(LLVM_TESTINGSUPPORT_LIBLIST ${LIBLIST} CACHE STRING "Library list for LLVMTestingSupport")
+ set(COMPILER_RT_HAS_LLVMTESTINGSUPPORT TRUE)
+ endif()
+ endif()
+
+ # Make use of LLVM CMake modules.
+ # --cmakedir is supported since llvm r291218 (4.0 release)
+ execute_process(
+ COMMAND ${LLVM_CONFIG_PATH} --cmakedir
+ RESULT_VARIABLE HAD_ERROR
+ OUTPUT_VARIABLE CONFIG_OUTPUT)
+ if(NOT HAD_ERROR)
+ string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH_FROM_LLVM_CONFIG)
+ file(TO_CMAKE_PATH ${LLVM_CMAKE_PATH_FROM_LLVM_CONFIG} LLVM_CMAKE_PATH)
+ else()
+ file(TO_CMAKE_PATH ${LLVM_BINARY_DIR} LLVM_BINARY_DIR_CMAKE_STYLE)
+ set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm")
+ endif()
- list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
- # Get some LLVM variables from LLVMConfig.
- include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
+ list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
+ # Get some LLVM variables from LLVMConfig.
+ include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
- set(LLVM_LIBRARY_OUTPUT_INTDIR
- ${LLVM_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
+ set(LLVM_LIBRARY_OUTPUT_INTDIR
+ ${LLVM_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
+ endif()
endmacro()
macro(construct_compiler_rt_default_triple)
@@ -272,11 +308,6 @@ macro(construct_compiler_rt_default_triple)
string(REPLACE "-" ";" TARGET_TRIPLE_LIST ${COMPILER_RT_DEFAULT_TARGET_TRIPLE})
list(GET TARGET_TRIPLE_LIST 0 COMPILER_RT_DEFAULT_TARGET_ARCH)
- list(GET TARGET_TRIPLE_LIST 1 COMPILER_RT_DEFAULT_TARGET_OS)
- list(LENGTH TARGET_TRIPLE_LIST TARGET_TRIPLE_LIST_LENGTH)
- if(TARGET_TRIPLE_LIST_LENGTH GREATER 2)
- list(GET TARGET_TRIPLE_LIST 2 COMPILER_RT_DEFAULT_TARGET_ABI)
- endif()
# Determine if test target triple is specified explicitly, and doesn't match the
# default.
if(NOT COMPILER_RT_DEFAULT_TARGET_TRIPLE STREQUAL TARGET_TRIPLE)
@@ -316,13 +347,15 @@ function(filter_builtin_sources output_var exclude_or_include excluded_list)
endfunction()
function(get_compiler_rt_target arch variable)
- if(ANDROID AND ${arch} STREQUAL "i386")
- set(target "i686${COMPILER_RT_OS_SUFFIX}-${COMPILER_RT_DEFAULT_TARGET_OS}")
+ string(FIND ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} "-" dash_index)
+ string(SUBSTRING ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} ${dash_index} -1 triple_suffix)
+ if(COMPILER_RT_DEFAULT_TARGET_ONLY)
+ # Use exact spelling when building only for the target specified to CMake.
+ set(target "${COMPILER_RT_DEFAULT_TARGET_TRIPLE}")
+ elseif(ANDROID AND ${arch} STREQUAL "i386")
+ set(target "i686${COMPILER_RT_OS_SUFFIX}${triple_suffix}")
else()
- set(target "${arch}-${COMPILER_RT_DEFAULT_TARGET_OS}")
- endif()
- if(COMPILER_RT_DEFAULT_TARGET_ABI)
- set(target "${target}-${COMPILER_RT_DEFAULT_TARGET_ABI}")
+ set(target "${arch}${triple_suffix}")
endif()
set(${variable} ${target} PARENT_SCOPE)
endfunction()
diff --git a/cmake/Modules/HandleCompilerRT.cmake b/cmake/Modules/HandleCompilerRT.cmake
index 855d0ff9df1c..61b7792789e7 100644
--- a/cmake/Modules/HandleCompilerRT.cmake
+++ b/cmake/Modules/HandleCompilerRT.cmake
@@ -4,12 +4,16 @@ function(find_compiler_rt_library name variable)
if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET)
list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}")
endif()
+ get_property(SANITIZER_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
+ string(REPLACE " " ";" SANITIZER_CXX_FLAGS "${SANITIZER_CXX_FLAGS}")
+ list(APPEND CLANG_COMMAND ${SANITIZER_CXX_FLAGS})
execute_process(
COMMAND ${CLANG_COMMAND}
RESULT_VARIABLE HAD_ERROR
OUTPUT_VARIABLE LIBRARY_FILE
)
string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
+ file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}")
if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}")
message(STATUS "Found compiler-rt ${name} library: ${LIBRARY_FILE}")
diff --git a/cmake/Modules/SanitizerUtils.cmake b/cmake/Modules/SanitizerUtils.cmake
index b6312426cacb..64d3ed92cb6e 100644
--- a/cmake/Modules/SanitizerUtils.cmake
+++ b/cmake/Modules/SanitizerUtils.cmake
@@ -30,7 +30,7 @@ macro(add_sanitizer_rt_symbols name)
add_custom_command(OUTPUT ${stamp}
COMMAND ${PYTHON_EXECUTABLE}
${SANITIZER_GEN_DYNAMIC_LIST} ${extra_args} $<TARGET_FILE:${target_name}>
- > $<TARGET_FILE:${target_name}>.syms
+ -o $<TARGET_FILE:${target_name}>.syms
COMMAND ${CMAKE_COMMAND} -E touch ${stamp}
DEPENDS ${target_name} ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -51,7 +51,15 @@ endmacro()
# This function is only used on Darwin, where undefined symbols must be specified
# in the linker invocation.
function(add_weak_symbols libname link_flags)
- file(STRINGS "${COMPILER_RT_SOURCE_DIR}/lib/${libname}/weak_symbols.txt" WEAK_SYMBOLS)
+ set(weak_symbols_file "${COMPILER_RT_SOURCE_DIR}/lib/${libname}/weak_symbols.txt")
+ file(STRINGS "${weak_symbols_file}" WEAK_SYMBOLS)
+ # Add this file as a configure-time dependency so that changes to this
+ # file trigger a re-configure. This is necessary so that `${link_flags}`
+ # is changed when appropriate.
+ set_property(
+ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ APPEND
+ PROPERTY CMAKE_CONFIGURE_DEPENDS "${weak_symbols_file}")
set(local_link_flags ${${link_flags}})
foreach(SYMBOL ${WEAK_SYMBOLS})
set(local_link_flags ${local_link_flags} -Wl,-U,${SYMBOL})
@@ -72,7 +80,7 @@ macro(add_sanitizer_rt_version_list name)
add_custom_command(OUTPUT ${vers}
COMMAND ${PYTHON_EXECUTABLE}
${SANITIZER_GEN_DYNAMIC_LIST} --version-list ${args}
- > ${vers}
+ -o ${vers}
DEPENDS ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA} ${ARG_LIBS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating version list for ${name}"
diff --git a/cmake/base-config-ix.cmake b/cmake/base-config-ix.cmake
index 91fe2494b476..6684d7371d68 100644
--- a/cmake/base-config-ix.cmake
+++ b/cmake/base-config-ix.cmake
@@ -8,6 +8,12 @@ include(CheckCXXSourceCompiles)
check_include_file(unwind.h HAVE_UNWIND_H)
+# Used by sanitizer_common and tests.
+check_include_file(rpc/xdr.h HAVE_RPC_XDR_H)
+if (NOT HAVE_RPC_XDR_H)
+ set(HAVE_RPC_XDR_H 0)
+endif()
+
# Top level target used to build all compiler-rt libraries.
add_custom_target(compiler-rt ALL)
add_custom_target(install-compiler-rt)
@@ -122,8 +128,6 @@ macro(test_targets)
# what version of MSVC to pretend to be so that the STL works.
set(MSVC_VERSION_FLAG "")
if (MSVC)
- # Find and run MSVC (not clang-cl) and get its version. This will tell
- # clang-cl what version of MSVC to pretend to be so that the STL works.
execute_process(COMMAND "$ENV{VSINSTALLDIR}/VC/bin/cl.exe"
OUTPUT_QUIET
ERROR_VARIABLE MSVC_COMPAT_VERSION
@@ -191,11 +195,11 @@ macro(test_targets)
# clang's default CPU's. In the 64-bit case, we must also specify the ABI
# since the default ABI differs between gcc and clang.
# FIXME: Ideally, we would build the N32 library too.
- test_target_arch(mipsel "" "-mips32r2" "--target=mipsel-linux-gnu")
- test_target_arch(mips64el "" "-mips64r2" "--target=mips64el-linux-gnu" "-mabi=64")
+ test_target_arch(mipsel "" "-mips32r2" "-mabi=32")
+ test_target_arch(mips64el "" "-mips64r2" "-mabi=64")
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "mips")
- test_target_arch(mips "" "-mips32r2" "--target=mips-linux-gnu")
- test_target_arch(mips64 "" "-mips64r2" "--target=mips64-linux-gnu" "-mabi=64")
+ test_target_arch(mips "" "-mips32r2" "-mabi=32")
+ test_target_arch(mips64 "" "-mips64r2" "-mabi=64")
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "arm")
if(WIN32)
test_target_arch(arm "" "" "")
diff --git a/cmake/builtin-config-ix.cmake b/cmake/builtin-config-ix.cmake
index a5704e5fed53..c4d0940f9f87 100644
--- a/cmake/builtin-config-ix.cmake
+++ b/cmake/builtin-config-ix.cmake
@@ -103,20 +103,6 @@ if(APPLE)
set(CAN_TARGET_${arch} 1)
endforeach()
- # Need to build a 10.4 compatible libclang_rt
- set(DARWIN_10.4_SYSROOT ${DARWIN_osx_SYSROOT})
- set(DARWIN_10.4_BUILTIN_MIN_VER 10.4)
- set(DARWIN_10.4_BUILTIN_MIN_VER_FLAG
- -mmacosx-version-min=${DARWIN_10.4_BUILTIN_MIN_VER})
- set(DARWIN_10.4_SKIP_CC_KEXT On)
- darwin_test_archs(10.4 DARWIN_10.4_ARCHS i386 x86_64)
- message(STATUS "OSX 10.4 supported builtin arches: ${DARWIN_10.4_ARCHS}")
- if(DARWIN_10.4_ARCHS)
- # don't include the Haswell slice in the 10.4 compatibility library
- list(REMOVE_ITEM DARWIN_10.4_ARCHS x86_64h)
- list(APPEND BUILTIN_SUPPORTED_OS 10.4)
- endif()
-
foreach(platform ${DARWIN_EMBEDDED_PLATFORMS})
if(DARWIN_${platform}sim_SYSROOT)
set(DARWIN_${platform}sim_BUILTIN_MIN_VER
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index f3935ffd6fd2..db5c4645dc0a 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -37,9 +37,23 @@ if (COMPILER_RT_HAS_NODEFAULTLIBS_FLAG)
elseif (COMPILER_RT_HAS_GCC_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES gcc)
endif ()
+ if (MINGW)
+ # Mingw64 requires quite a few "C" runtime libraries in order for basic
+ # programs to link successfully with -nodefaultlibs.
+ if (COMPILER_RT_USE_BUILTINS_LIBRARY)
+ set(MINGW_RUNTIME ${COMPILER_RT_BUILTINS_LIBRARY})
+ else ()
+ set(MINGW_RUNTIME gcc_s gcc)
+ endif()
+ set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32
+ shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME}
+ moldname mingwex msvcrt)
+ list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES})
+ endif()
endif ()
# CodeGen options.
+check_c_compiler_flag(-ffreestanding COMPILER_RT_HAS_FFREESTANDING_FLAG)
check_cxx_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG)
check_cxx_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG)
check_cxx_compiler_flag(-fno-builtin COMPILER_RT_HAS_FNO_BUILTIN_FLAG)
@@ -51,7 +65,6 @@ check_cxx_compiler_flag(-fno-sanitize=safe-stack COMPILER_RT_HAS_FNO_SANITIZE_SA
check_cxx_compiler_flag(-fvisibility=hidden COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG)
check_cxx_compiler_flag(-frtti COMPILER_RT_HAS_FRTTI_FLAG)
check_cxx_compiler_flag(-fno-rtti COMPILER_RT_HAS_FNO_RTTI_FLAG)
-check_cxx_compiler_flag(-ffreestanding COMPILER_RT_HAS_FFREESTANDING_FLAG)
check_cxx_compiler_flag("-Werror -fno-function-sections" COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG)
check_cxx_compiler_flag(-std=c++11 COMPILER_RT_HAS_STD_CXX11_FLAG)
check_cxx_compiler_flag(-ftls-model=initial-exec COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC)
@@ -105,6 +118,21 @@ check_library_exists(dl dlopen "" COMPILER_RT_HAS_LIBDL)
check_library_exists(rt shm_open "" COMPILER_RT_HAS_LIBRT)
check_library_exists(m pow "" COMPILER_RT_HAS_LIBM)
check_library_exists(pthread pthread_create "" COMPILER_RT_HAS_LIBPTHREAD)
+
+# Look for terminfo library, used in unittests that depend on LLVMSupport.
+if(LLVM_ENABLE_TERMINFO)
+ foreach(library terminfo tinfo curses ncurses ncursesw)
+ string(TOUPPER ${library} library_suffix)
+ check_library_exists(
+ ${library} setupterm "" COMPILER_RT_HAS_TERMINFO_${library_suffix})
+ if(COMPILER_RT_HAS_TERMINFO_${library_suffix})
+ set(COMPILER_RT_HAS_TERMINFO TRUE)
+ set(COMPILER_RT_TERMINFO_LIB "${library}")
+ break()
+ endif()
+ endforeach()
+endif()
+
if (ANDROID AND COMPILER_RT_HAS_LIBDL)
# Android's libstdc++ has a dependency on libdl.
list(APPEND CMAKE_REQUIRED_LIBRARIES dl)
@@ -501,7 +529,8 @@ list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")
if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND
(OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|OpenBSD|Fuchsia|SunOS" OR
- (OS_NAME MATCHES "Windows" AND (NOT MINGW AND NOT CYGWIN))))
+ (OS_NAME MATCHES "Windows" AND NOT CYGWIN AND
+ (NOT MINGW OR CMAKE_CXX_COMPILER_ID MATCHES "Clang"))))
set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE)
else()
set(COMPILER_RT_HAS_SANITIZER_COMMON FALSE)
@@ -557,7 +586,7 @@ else()
endif()
if (PROFILE_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND
- OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|Fuchsia|SunOS")
+ OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|Fuchsia|SunOS|NetBSD")
set(COMPILER_RT_HAS_PROFILE TRUE)
else()
set(COMPILER_RT_HAS_PROFILE FALSE)
@@ -598,7 +627,7 @@ else()
endif()
if (COMPILER_RT_HAS_SANITIZER_COMMON AND ESAN_SUPPORTED_ARCH AND
- OS_NAME MATCHES "Linux")
+ OS_NAME MATCHES "Linux|FreeBSD")
set(COMPILER_RT_HAS_ESAN TRUE)
else()
set(COMPILER_RT_HAS_ESAN FALSE)
@@ -612,14 +641,17 @@ else()
endif()
if (COMPILER_RT_HAS_SANITIZER_COMMON AND XRAY_SUPPORTED_ARCH AND
- OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|OpenBSD")
+ OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|OpenBSD|Fuchsia")
set(COMPILER_RT_HAS_XRAY TRUE)
else()
set(COMPILER_RT_HAS_XRAY FALSE)
endif()
if (COMPILER_RT_HAS_SANITIZER_COMMON AND FUZZER_SUPPORTED_ARCH AND
- OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|FreeBSD|OpenBSD|Fuchsia")
+ OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|FreeBSD|OpenBSD|Fuchsia|Windows" AND
+ # TODO: Support builds with MSVC.
+ NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" AND
+ NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
set(COMPILER_RT_HAS_FUZZER TRUE)
else()
set(COMPILER_RT_HAS_FUZZER FALSE)
diff --git a/include/sanitizer/allocator_interface.h b/include/sanitizer/allocator_interface.h
index 89f328301db3..e44c4a13ed67 100644
--- a/include/sanitizer/allocator_interface.h
+++ b/include/sanitizer/allocator_interface.h
@@ -82,7 +82,6 @@ extern "C" {
Currently available with ASan only.
*/
void __sanitizer_purge_allocator(void);
-
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/include/sanitizer/common_interface_defs.h b/include/sanitizer/common_interface_defs.h
index d11cb1addc27..bf015eb237cd 100644
--- a/include/sanitizer/common_interface_defs.h
+++ b/include/sanitizer/common_interface_defs.h
@@ -124,6 +124,12 @@ extern "C" {
// Symbolizes the supplied 'pc' using the format string 'fmt'.
// Outputs at most 'out_buf_size' bytes into 'out_buf'.
+ // If 'out_buf' is not empty then output is zero or more non empty C strings
+ // followed by single empty C string. Multiple strings can be returned if PC
+ // corresponds to inlined function. Inlined frames are printed in the order
+ // from "most-inlined" to the "least-inlined", so the last frame should be the
+ // not inlined function.
+ // Inlined frames can be removed with 'symbolize_inline_frames=0'.
// The format syntax is described in
// lib/sanitizer_common/sanitizer_stacktrace_printer.h.
void __sanitizer_symbolize_pc(void *pc, const char *fmt, char *out_buf,
diff --git a/include/sanitizer/hwasan_interface.h b/include/sanitizer/hwasan_interface.h
index 0c306cf279e2..1affd875a11b 100644
--- a/include/sanitizer/hwasan_interface.h
+++ b/include/sanitizer/hwasan_interface.h
@@ -19,6 +19,12 @@
#ifdef __cplusplus
extern "C" {
#endif
+ // Initialize shadow but not the rest of the runtime.
+ // Does not call libc unless there is an error.
+ // Can be called multiple times, or not at all (in which case shadow will
+ // be initialized in compiler-inserted __hwasan_init() call).
+ void __hwasan_shadow_init(void);
+
// This function may be optionally provided by user and should return
// a string containing HWASan runtime options. See asan_flags.h for details.
const char* __hwasan_default_options(void);
@@ -26,6 +32,51 @@ extern "C" {
void __hwasan_enable_allocator_tagging(void);
void __hwasan_disable_allocator_tagging(void);
+ // Mark region of memory with the given tag. Both address and size need to be
+ // 16-byte aligned.
+ void __hwasan_tag_memory(const volatile void *p, unsigned char tag,
+ size_t size);
+
+ /// Set pointer tag. Previous tag is lost.
+ void *__hwasan_tag_pointer(const volatile void *p, unsigned char tag);
+
+ // Set memory tag from the current SP address to the given address to zero.
+ // This is meant to annotate longjmp and other non-local jumps.
+ // This function needs to know the (almost) exact destination frame address;
+ // clearing shadow for the entire thread stack like __asan_handle_no_return
+ // does would cause false reports.
+ void __hwasan_handle_longjmp(const void *sp_dst);
+
+ // Libc hook for thread creation. Should be called in the child thread before
+ // any instrumented code.
+ void __hwasan_thread_enter();
+
+ // Libc hook for thread destruction. No instrumented code should run after
+ // this call.
+ void __hwasan_thread_exit();
+
+ // Print shadow and origin for the memory range to stderr in a human-readable
+ // format.
+ void __hwasan_print_shadow(const volatile void *x, size_t size);
+
+ // Print one-line report about the memory usage of the current process.
+ void __hwasan_print_memory_usage();
+
+ int __sanitizer_posix_memalign(void **memptr, size_t alignment, size_t size);
+ void * __sanitizer_memalign(size_t alignment, size_t size);
+ void * __sanitizer_aligned_alloc(size_t alignment, size_t size);
+ void * __sanitizer___libc_memalign(size_t alignment, size_t size);
+ void * __sanitizer_valloc(size_t size);
+ void * __sanitizer_pvalloc(size_t size);
+ void __sanitizer_free(void *ptr);
+ void __sanitizer_cfree(void *ptr);
+ size_t __sanitizer_malloc_usable_size(const void *ptr);
+ struct mallinfo __sanitizer_mallinfo();
+ int __sanitizer_mallopt(int cmd, int value);
+ void __sanitizer_malloc_stats(void);
+ void * __sanitizer_calloc(size_t nmemb, size_t size);
+ void * __sanitizer_realloc(void *ptr, size_t size);
+ void * __sanitizer_malloc(size_t size);
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/include/sanitizer/netbsd_syscall_hooks.h b/include/sanitizer/netbsd_syscall_hooks.h
index 4c6c6a88af29..b69f3d2be39f 100644
--- a/include/sanitizer/netbsd_syscall_hooks.h
+++ b/include/sanitizer/netbsd_syscall_hooks.h
@@ -21,8 +21,8 @@
// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
//
// Generated with: generate_netbsd_syscalls.awk
-// Generated date: 2018-03-03
-// Generated from: syscalls.master,v 1.291 2018/01/06 16:41:23 kamil Exp
+// Generated date: 2018-10-30
+// Generated from: syscalls.master,v 1.293 2018/07/31 13:00:13 rjs Exp
//
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H
@@ -986,7 +986,15 @@
#define __sanitizer_syscall_post_fpathconf(res, fd, name) \
__sanitizer_syscall_post_impl_fpathconf(res, (long long)(fd), \
(long long)(name))
-/* syscall 193 has been skipped */
+#define __sanitizer_syscall_pre_getsockopt2(s, level, name, val, avalsize) \
+ __sanitizer_syscall_pre_impl_getsockopt2( \
+ (long long)(s), (long long)(level), (long long)(name), (long long)(val), \
+ (long long)(avalsize))
+#define __sanitizer_syscall_post_getsockopt2(res, s, level, name, val, \
+ avalsize) \
+ __sanitizer_syscall_post_impl_getsockopt2( \
+ res, (long long)(s), (long long)(level), (long long)(name), \
+ (long long)(val), (long long)(avalsize))
#define __sanitizer_syscall_pre_getrlimit(which, rlp) \
__sanitizer_syscall_pre_impl_getrlimit((long long)(which), (long long)(rlp))
#define __sanitizer_syscall_post_getrlimit(res, which, rlp) \
@@ -1752,18 +1760,8 @@
__sanitizer_syscall_post_impl___sigaction_sigtramp( \
res, (long long)(signum), (long long)(nsa), (long long)(osa), \
(long long)(tramp), (long long)(vers))
-#define __sanitizer_syscall_pre_pmc_get_info(ctr, op, args) \
- __sanitizer_syscall_pre_impl_pmc_get_info((long long)(ctr), (long long)(op), \
- (long long)(args))
-#define __sanitizer_syscall_post_pmc_get_info(res, ctr, op, args) \
- __sanitizer_syscall_post_impl_pmc_get_info( \
- res, (long long)(ctr), (long long)(op), (long long)(args))
-#define __sanitizer_syscall_pre_pmc_control(ctr, op, args) \
- __sanitizer_syscall_pre_impl_pmc_control((long long)(ctr), (long long)(op), \
- (long long)(args))
-#define __sanitizer_syscall_post_pmc_control(res, ctr, op, args) \
- __sanitizer_syscall_post_impl_pmc_control( \
- res, (long long)(ctr), (long long)(op), (long long)(args))
+/* syscall 341 has been skipped */
+/* syscall 342 has been skipped */
#define __sanitizer_syscall_pre_rasctl(addr, len, op) \
__sanitizer_syscall_pre_impl_rasctl((long long)(addr), (long long)(len), \
(long long)(op))
@@ -3444,7 +3442,13 @@ void __sanitizer_syscall_post_impl_pathconf(long long res, long long path,
void __sanitizer_syscall_pre_impl_fpathconf(long long fd, long long name);
void __sanitizer_syscall_post_impl_fpathconf(long long res, long long fd,
long long name);
-/* syscall 193 has been skipped */
+void __sanitizer_syscall_pre_impl_getsockopt2(long long s, long long level,
+ long long name, long long val,
+ long long avalsize);
+void __sanitizer_syscall_post_impl_getsockopt2(long long res, long long s,
+ long long level, long long name,
+ long long val,
+ long long avalsize);
void __sanitizer_syscall_pre_impl_getrlimit(long long which, long long rlp);
void __sanitizer_syscall_post_impl_getrlimit(long long res, long long which,
long long rlp);
@@ -4001,14 +4005,8 @@ void __sanitizer_syscall_pre_impl___sigaction_sigtramp(long long signum,
void __sanitizer_syscall_post_impl___sigaction_sigtramp(
long long res, long long signum, long long nsa, long long osa,
long long tramp, long long vers);
-void __sanitizer_syscall_pre_impl_pmc_get_info(long long ctr, long long op,
- long long args);
-void __sanitizer_syscall_post_impl_pmc_get_info(long long res, long long ctr,
- long long op, long long args);
-void __sanitizer_syscall_pre_impl_pmc_control(long long ctr, long long op,
- long long args);
-void __sanitizer_syscall_post_impl_pmc_control(long long res, long long ctr,
- long long op, long long args);
+/* syscall 341 has been skipped */
+/* syscall 342 has been skipped */
void __sanitizer_syscall_pre_impl_rasctl(long long addr, long long len,
long long op);
void __sanitizer_syscall_post_impl_rasctl(long long res, long long addr,
diff --git a/include/xray/xray_log_interface.h b/include/xray/xray_log_interface.h
index 5f8b3a4a06a4..399467860e73 100644
--- a/include/xray/xray_log_interface.h
+++ b/include/xray/xray_log_interface.h
@@ -158,8 +158,8 @@ struct XRayLogImpl {
/// The log initialization routine provided by the implementation, always
/// provided with the following parameters:
///
- /// - buffer size
- /// - maximum number of buffers
+ /// - buffer size (unused)
+ /// - maximum number of buffers (unused)
/// - a pointer to an argument struct that the implementation MUST handle
/// - the size of the argument struct
///
@@ -355,25 +355,4 @@ XRayLogFlushStatus __xray_log_process_buffers(void (*Processor)(const char *,
} // extern "C"
-namespace __xray {
-
-/// DEPRECATED: Use __xray_log_init_mode(...) instead, and provide flag
-/// configuration strings to set the options instead.
-/// Options used by the LLVM XRay FDR logging implementation.
-struct FDRLoggingOptions {
- bool ReportErrors = false;
- int Fd = -1;
-};
-
-/// DEPRECATED: Use __xray_log_init_mode(...) instead, and provide flag
-/// configuration strings to set the options instead.
-/// Options used by the LLVM XRay Basic (Naive) logging implementation.
-struct BasicLoggingOptions {
- int DurationFilterMicros = 0;
- size_t MaxStackDepth = 0;
- size_t ThreadBufferSize = 0;
-};
-
-} // namespace __xray
-
#endif // XRAY_XRAY_LOG_INTERFACE_H
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index 2ae5c85ecefb..726da27d052f 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -75,6 +75,14 @@ append_rtti_flag(OFF ASAN_CFLAGS)
set(ASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS})
+if(ANDROID)
+# Put most Sanitizer shared libraries in the global group. For more details, see
+# android-changes-for-ndk-developers.md#changes-to-library-search-order
+ if (COMPILER_RT_HAS_Z_GLOBAL)
+ list(APPEND ASAN_DYNAMIC_LINK_FLAGS -Wl,-z,global)
+ endif()
+endif()
+
set(ASAN_DYNAMIC_DEFINITIONS
${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1)
append_list_if(WIN32 INTERCEPTION_DYNAMIC_CRT ASAN_DYNAMIC_DEFINITIONS)
@@ -91,6 +99,11 @@ append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS)
+append_list_if(MINGW "${MINGW_LIBRARIES}" ASAN_DYNAMIC_LIBS)
+
+if (TARGET cxx-headers OR HAVE_LIBCXX)
+ set(ASAN_DEPS cxx-headers)
+endif()
# Compile ASan sources into an object library.
@@ -100,7 +113,8 @@ add_compiler_rt_object_libraries(RTAsan_dynamic
SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
ADDITIONAL_HEADERS ${ASAN_HEADERS}
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
- DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS}
+ DEPS ${ASAN_DEPS})
if(NOT APPLE)
add_compiler_rt_object_libraries(RTAsan
@@ -108,26 +122,30 @@ if(NOT APPLE)
SOURCES ${ASAN_SOURCES}
ADDITIONAL_HEADERS ${ASAN_HEADERS}
CFLAGS ${ASAN_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS})
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ DEPS ${ASAN_DEPS})
add_compiler_rt_object_libraries(RTAsan_cxx
ARCHS ${ASAN_SUPPORTED_ARCH}
SOURCES ${ASAN_CXX_SOURCES}
ADDITIONAL_HEADERS ${ASAN_HEADERS}
CFLAGS ${ASAN_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS})
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ DEPS ${ASAN_DEPS})
add_compiler_rt_object_libraries(RTAsan_preinit
ARCHS ${ASAN_SUPPORTED_ARCH}
SOURCES ${ASAN_PREINIT_SOURCES}
ADDITIONAL_HEADERS ${ASAN_HEADERS}
CFLAGS ${ASAN_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS})
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ DEPS ${ASAN_DEPS})
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc "")
add_compiler_rt_object_libraries(RTAsan_dynamic_version_script_dummy
ARCHS ${ASAN_SUPPORTED_ARCH}
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
- DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS}
+ DEPS ${ASAN_DEPS})
endif()
# Build ASan runtimes shipped with Clang.
@@ -138,6 +156,7 @@ if(APPLE)
add_weak_symbols("lsan" WEAK_SYMBOL_LINK_FLAGS)
add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS)
add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
+ add_weak_symbols("xray" WEAK_SYMBOL_LINK_FLAGS)
add_compiler_rt_runtime(clang_rt.asan
SHARED
@@ -215,13 +234,14 @@ else()
endif()
set(ASAN_DYNAMIC_WEAK_INTERCEPTION)
- if (MSVC)
+ if (WIN32)
add_compiler_rt_object_libraries(AsanWeakInterception
${SANITIZER_COMMON_SUPPORTED_OS}
ARCHS ${arch}
SOURCES asan_win_weak_interception.cc
CFLAGS ${ASAN_CFLAGS} -DSANITIZER_DYNAMIC
- DEFS ${ASAN_COMMON_DEFINITIONS})
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ DEPS ${ASAN_DEPS})
set(ASAN_DYNAMIC_WEAK_INTERCEPTION
AsanWeakInterception
UbsanWeakInterception
@@ -266,7 +286,8 @@ else()
SOURCES asan_globals_win.cc
asan_win_dll_thunk.cc
CFLAGS ${ASAN_CFLAGS} -DSANITIZER_DLL_THUNK
- DEFS ${ASAN_COMMON_DEFINITIONS})
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ DEPS ${ASAN_DEPS})
add_compiler_rt_runtime(clang_rt.asan_dll_thunk
STATIC
@@ -291,7 +312,8 @@ else()
SOURCES asan_globals_win.cc
asan_win_dynamic_runtime_thunk.cc
CFLAGS ${ASAN_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS}
- DEFS ${ASAN_COMMON_DEFINITIONS})
+ DEFS ${ASAN_COMMON_DEFINITIONS}
+ DEPS ${ASAN_DEPS})
add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk
STATIC
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index 93d6f29c5bf5..c9b37dc7a6d4 100644
--- a/lib/asan/asan_allocator.h
+++ b/lib/asan/asan_allocator.h
@@ -148,6 +148,7 @@ const uptr kAllocatorSpace = 0x600000000000ULL;
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
typedef DefaultSizeClassMap SizeClassMap;
# endif
+template <typename AddressSpaceViewTy>
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
static const uptr kSpaceBeg = kAllocatorSpace;
static const uptr kSpaceSize = kAllocatorSize;
@@ -155,37 +156,57 @@ struct AP64 { // Allocator64 parameters. Deliberately using a short name.
typedef __asan::SizeClassMap SizeClassMap;
typedef AsanMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
+ using AddressSpaceView = AddressSpaceViewTy;
};
-typedef SizeClassAllocator64<AP64> PrimaryAllocator;
+template <typename AddressSpaceView>
+using PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
+using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
#else // Fallback to SizeClassAllocator32.
static const uptr kRegionSizeLog = 20;
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
# if SANITIZER_WORDSIZE == 32
-typedef FlatByteMap<kNumRegions> ByteMap;
+template <typename AddressSpaceView>
+using ByteMapASVT = FlatByteMap<kNumRegions, AddressSpaceView>;
# elif SANITIZER_WORDSIZE == 64
-typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+template <typename AddressSpaceView>
+using ByteMapASVT =
+ TwoLevelByteMap<(kNumRegions >> 12), 1 << 12, AddressSpaceView>;
# endif
typedef CompactSizeClassMap SizeClassMap;
+template <typename AddressSpaceViewTy>
struct AP32 {
static const uptr kSpaceBeg = 0;
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
static const uptr kMetadataSize = 16;
typedef __asan::SizeClassMap SizeClassMap;
static const uptr kRegionSizeLog = __asan::kRegionSizeLog;
- typedef __asan::ByteMap ByteMap;
+ using AddressSpaceView = AddressSpaceViewTy;
+ using ByteMap = __asan::ByteMapASVT<AddressSpaceView>;
typedef AsanMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
};
-typedef SizeClassAllocator32<AP32> PrimaryAllocator;
+template <typename AddressSpaceView>
+using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView> >;
+using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
#endif // SANITIZER_CAN_USE_ALLOCATOR64
static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
-typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
-typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
-typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
- SecondaryAllocator> AsanAllocator;
-
+template <typename AddressSpaceView>
+using AllocatorCacheASVT =
+ SizeClassAllocatorLocalCache<PrimaryAllocatorASVT<AddressSpaceView>>;
+using AllocatorCache = AllocatorCacheASVT<LocalAddressSpaceView>;
+
+template <typename AddressSpaceView>
+using SecondaryAllocatorASVT =
+ LargeMmapAllocator<AsanMapUnmapCallback, DefaultLargeMmapAllocatorPtrArray,
+ AddressSpaceView>;
+template <typename AddressSpaceView>
+using AsanAllocatorASVT =
+ CombinedAllocator<PrimaryAllocatorASVT<AddressSpaceView>,
+ AllocatorCacheASVT<AddressSpaceView>,
+ SecondaryAllocatorASVT<AddressSpaceView>>;
+using AsanAllocator = AsanAllocatorASVT<LocalAddressSpaceView>;
struct AsanThreadLocalMallocStorage {
uptr quarantine_cache[16];
diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc
index 33d0613f79f4..0ecd30dcacfd 100644
--- a/lib/asan/asan_errors.cc
+++ b/lib/asan/asan_errors.cc
@@ -125,9 +125,8 @@ void ErrorAllocTypeMismatch::Print() {
Decorator d;
Printf("%s", d.Error());
Report("ERROR: AddressSanitizer: %s (%s vs %s) on %p\n",
- scariness.GetDescription(),
- alloc_names[alloc_type], dealloc_names[dealloc_type],
- addr_description.addr);
+ scariness.GetDescription(), alloc_names[alloc_type],
+ dealloc_names[dealloc_type], addr_description.Address());
Printf("%s", d.Default());
CHECK_GT(dealloc_stack->size, 0);
scariness.Print();
diff --git a/lib/asan/asan_errors.h b/lib/asan/asan_errors.h
index 574197ebff86..7ddd7e94e0fc 100644
--- a/lib/asan/asan_errors.h
+++ b/lib/asan/asan_errors.h
@@ -110,8 +110,8 @@ struct ErrorFreeNotMalloced : ErrorBase {
struct ErrorAllocTypeMismatch : ErrorBase {
const BufferedStackTrace *dealloc_stack;
- HeapAddressDescription addr_description;
AllocType alloc_type, dealloc_type;
+ AddressDescription addr_description;
ErrorAllocTypeMismatch() = default; // (*)
ErrorAllocTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
@@ -119,9 +119,8 @@ struct ErrorAllocTypeMismatch : ErrorBase {
: ErrorBase(tid, 10, "alloc-dealloc-mismatch"),
dealloc_stack(stack),
alloc_type(alloc_type_),
- dealloc_type(dealloc_type_) {
- GetHeapAddressInformation(addr, 1, &addr_description);
- };
+ dealloc_type(dealloc_type_),
+ addr_description(addr, 1, false) {}
void Print();
};
diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc
index 4af94c56fca0..a9c97d53b31f 100644
--- a/lib/asan/asan_flags.inc
+++ b/lib/asan/asan_flags.inc
@@ -152,8 +152,6 @@ ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
ASAN_FLAG(bool, halt_on_error, true,
"Crash the program after printing the first error report "
"(WARNING: USE AT YOUR OWN RISK!)")
-ASAN_FLAG(bool, use_odr_indicator, false,
- "Use special ODR indicator symbol for ODR violation detection")
ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true,
"realloc(p, 0) is equivalent to free(p) by default (Same as the "
"POSIX standard). If set to false, realloc(p, 0) will return a "
diff --git a/lib/asan/asan_fuchsia.cc b/lib/asan/asan_fuchsia.cc
index 0b5bff4f565e..34399c92310b 100644
--- a/lib/asan/asan_fuchsia.cc
+++ b/lib/asan/asan_fuchsia.cc
@@ -190,6 +190,13 @@ static void ThreadExitHook(void *hook, uptr os_id) {
AsanThread::TSDDtor(per_thread);
}
+bool HandleDlopenInit() {
+ // Not supported on this platform.
+ static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+ "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+ return false;
+}
+
} // namespace __asan
// These are declared (in extern "C") by <zircon/sanitizer.h>.
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index 898f7f40d31b..146234ac6c64 100644
--- a/lib/asan/asan_globals.cc
+++ b/lib/asan/asan_globals.cc
@@ -83,9 +83,11 @@ static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
}
static void ReportGlobal(const Global &g, const char *prefix) {
- Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
- prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
- g.module_name, g.has_dynamic_init);
+ Report(
+ "%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu "
+ "odr_indicator=%p\n",
+ prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
+ g.module_name, g.has_dynamic_init, (void *)g.odr_indicator);
if (g.location) {
Report(" location (%p): name=%s[%p], %d %d\n", g.location,
g.location->filename, g.location->filename, g.location->line_no,
@@ -133,6 +135,9 @@ enum GlobalSymbolState {
// this method in case compiler instruments global variables through their
// local aliases.
static void CheckODRViolationViaIndicator(const Global *g) {
+ // Instrumentation requests to skip ODR check.
+ if (g->odr_indicator == UINTPTR_MAX)
+ return;
u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
if (*odr_indicator == UNREGISTERED) {
*odr_indicator = REGISTERED;
@@ -183,9 +188,7 @@ static void CheckODRViolationViaPoisoning(const Global *g) {
// This routine chooses between two different methods of ODR violation
// detection.
static inline bool UseODRIndicator(const Global *g) {
- // Use ODR indicator method iff use_odr_indicator flag is set and
- // indicator symbol address is not 0.
- return flags()->use_odr_indicator && g->odr_indicator > 0;
+ return g->odr_indicator > 0;
}
// Register a global variable.
@@ -248,7 +251,7 @@ static void UnregisterGlobal(const Global *g) {
// implementation. It might not be worth doing anyway.
// Release ODR indicator.
- if (UseODRIndicator(g)) {
+ if (UseODRIndicator(g) && g->odr_indicator != UINTPTR_MAX) {
u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
*odr_indicator = UNREGISTERED;
}
diff --git a/lib/asan/asan_globals_win.cc b/lib/asan/asan_globals_win.cc
index 29ab5ebf16d4..0e75992bfc8d 100644
--- a/lib/asan/asan_globals_win.cc
+++ b/lib/asan/asan_globals_win.cc
@@ -29,7 +29,7 @@ static void call_on_globals(void (*hook)(__asan_global *, uptr)) {
__asan_global *end = &__asan_globals_end;
uptr bytediff = (uptr)end - (uptr)start;
if (bytediff % sizeof(__asan_global) != 0) {
-#ifdef SANITIZER_DLL_THUNK
+#if defined(SANITIZER_DLL_THUNK) || defined(SANITIZER_DYNAMIC_RUNTIME_THUNK)
__debugbreak();
#else
CHECK("corrupt asan global array");
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 654878cd15f0..57869497c7d3 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -111,6 +111,11 @@ void *AsanDlSymNext(const char *sym);
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name);
+// Returns `true` iff most of ASan init process should be skipped due to the
+// ASan library being loaded via `dlopen()`. Platforms may perform any
+// `dlopen()` specific initialization inside this function.
+bool HandleDlopenInit();
+
// Add convenient macro for interface functions that may be represented as
// weak hooks.
#define ASAN_MALLOC_HOOK(ptr, size) \
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 625f32d408df..a150b1955d60 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -248,6 +248,13 @@ void *AsanDlSymNext(const char *sym) {
return dlsym(RTLD_NEXT, sym);
}
+bool HandleDlopenInit() {
+ // Not supported on this platform.
+ static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+ "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+ return false;
+}
+
} // namespace __asan
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc
index 76bdff999d62..0a534fe21168 100644
--- a/lib/asan/asan_malloc_linux.cc
+++ b/lib/asan/asan_malloc_linux.cc
@@ -209,7 +209,7 @@ INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
}
INTERCEPTOR(int, mallopt, int cmd, int value) {
- return -1;
+ return 0;
}
#endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index 733ba2d86e13..27281f1bc834 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -61,4 +61,25 @@ using namespace __asan;
#include "sanitizer_common/sanitizer_malloc_mac.inc"
+namespace COMMON_MALLOC_NAMESPACE {
+bool HandleDlopenInit() {
+ static_assert(SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+ "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be true");
+ // We have no reliable way of knowing how we are being loaded
+ // so make it a requirement on Apple platforms to set this environment
+ // variable to indicate that we want to perform initialization via
+ // dlopen().
+ auto init_str = GetEnv("APPLE_ASAN_INIT_FOR_DLOPEN");
+ if (!init_str)
+ return false;
+ if (internal_strncmp(init_str, "1", 1) != 0)
+ return false;
+ // When we are loaded via `dlopen()` path we still initialize the malloc zone
+ // so Symbolication clients (e.g. `leaks`) that load the ASan allocator can
+ // find an initialized malloc zone.
+ InitMallocZoneFields();
+ return true;
+}
+} // namespace COMMON_MALLOC_NAMESPACE
+
#endif
diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc
index efa058243979..887936431931 100644
--- a/lib/asan/asan_malloc_win.cc
+++ b/lib/asan/asan_malloc_win.cc
@@ -14,8 +14,17 @@
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_WINDOWS
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
+// Intentionally not including windows.h here, to avoid the risk of
+// pulling in conflicting declarations of these functions. (With mingw-w64,
+// there's a risk of windows.h pulling in stdint.h.)
+typedef int BOOL;
+typedef void *HANDLE;
+typedef const void *LPCVOID;
+typedef void *LPVOID;
+
+#define HEAP_ZERO_MEMORY 0x00000008
+#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010
+
#include "asan_allocator.h"
#include "asan_interceptors.h"
@@ -125,13 +134,18 @@ void *_recalloc_base(void *p, size_t n, size_t elem_size) {
}
ALLOCATION_FUNCTION_ATTRIBUTE
-size_t _msize(const void *ptr) {
+size_t _msize(void *ptr) {
GET_CURRENT_PC_BP_SP;
(void)sp;
return asan_malloc_usable_size(ptr, pc, bp);
}
ALLOCATION_FUNCTION_ATTRIBUTE
+size_t _msize_base(void *ptr) {
+ return _msize(ptr);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
void *_expand(void *memblock, size_t size) {
// _expand is used in realloc-like functions to resize the buffer if possible.
// We don't want memory to stand still while resizing buffers, so return 0.
@@ -226,6 +240,7 @@ void ReplaceSystemMalloc() {
TryToOverrideFunction("_recalloc_base", (uptr)_recalloc);
TryToOverrideFunction("_recalloc_crt", (uptr)_recalloc);
TryToOverrideFunction("_msize", (uptr)_msize);
+ TryToOverrideFunction("_msize_base", (uptr)_msize);
TryToOverrideFunction("_expand", (uptr)_expand);
TryToOverrideFunction("_expand_base", (uptr)_expand);
diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc
index 30efd61a9680..e6053c1fe87f 100644
--- a/lib/asan/asan_new_delete.cc
+++ b/lib/asan/asan_new_delete.cc
@@ -26,7 +26,7 @@
// anyway by passing extra -export flags to the linker, which is exactly that
// dllexport would normally do. We need to export them in order to make the
// VS2015 dynamic CRT (MD) work.
-#if SANITIZER_WINDOWS
+#if SANITIZER_WINDOWS && defined(_MSC_VER)
#define CXX_OPERATOR_ATTRIBUTE
#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym))
#ifdef _WIN64
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index 17c28b0aea2a..ca99c04b3ad8 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -40,6 +40,51 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
// ---------------------- TSD ---------------- {{{1
+#if SANITIZER_NETBSD || SANITIZER_FREEBSD
+// Thread Static Data cannot be used in early init on NetBSD and FreeBSD.
+// Reuse the Asan TSD API for compatibility with existing code
+// with an alternative implementation.
+
+static void (*tsd_destructor)(void *tsd) = nullptr;
+
+struct tsd_key {
+ tsd_key() : key(nullptr) {}
+ ~tsd_key() {
+ CHECK(tsd_destructor);
+ if (key)
+ (*tsd_destructor)(key);
+ }
+ void *key;
+};
+
+static thread_local struct tsd_key key;
+
+void AsanTSDInit(void (*destructor)(void *tsd)) {
+ CHECK(!tsd_destructor);
+ tsd_destructor = destructor;
+}
+
+void *AsanTSDGet() {
+ CHECK(tsd_destructor);
+ return key.key;
+}
+
+void AsanTSDSet(void *tsd) {
+ CHECK(tsd_destructor);
+ CHECK(tsd);
+ CHECK(!key.key);
+ key.key = tsd;
+}
+
+void PlatformTSDDtor(void *tsd) {
+ CHECK(tsd_destructor);
+ CHECK_EQ(key.key, tsd);
+ key.key = nullptr;
+ // Make sure that signal handler can not see a stale current thread pointer.
+ atomic_signal_fence(memory_order_seq_cst);
+ AsanThread::TSDDtor(tsd);
+}
+#else
static pthread_key_t tsd_key;
static bool tsd_key_inited = false;
void AsanTSDInit(void (*destructor)(void *tsd)) {
@@ -67,6 +112,7 @@ void PlatformTSDDtor(void *tsd) {
}
AsanThread::TSDDtor(tsd);
}
+#endif
} // namespace __asan
#endif // SANITIZER_POSIX
diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h
index f7153d4810d0..b0c167dda756 100644
--- a/lib/asan/asan_report.h
+++ b/lib/asan/asan_report.h
@@ -12,6 +12,9 @@
// ASan-private header for error reporting functions.
//===----------------------------------------------------------------------===//
+#ifndef ASAN_REPORT_H
+#define ASAN_REPORT_H
+
#include "asan_allocator.h"
#include "asan_internal.h"
#include "asan_thread.h"
@@ -92,3 +95,4 @@ void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
BufferedStackTrace *stack);
} // namespace __asan
+#endif // ASAN_REPORT_H
diff --git a/lib/asan/asan_rtems.cc b/lib/asan/asan_rtems.cc
index a4af940057eb..b48cc6a75d78 100644
--- a/lib/asan/asan_rtems.cc
+++ b/lib/asan/asan_rtems.cc
@@ -213,6 +213,12 @@ static void HandleExit() {
}
}
+bool HandleDlopenInit() {
+ // Not supported on this platform.
+ static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+ "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+ return false;
+}
} // namespace __asan
// These are declared (in extern "C") by <some_path/sanitizer.h>.
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 4cff736f213a..13344f3b8887 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -383,6 +383,19 @@ void PrintAddressSpaceLayout() {
kHighShadowBeg > kMidMemEnd);
}
+#if defined(__thumb__) && defined(__linux__)
+#define START_BACKGROUND_THREAD_IN_ASAN_INTERNAL
+#endif
+
+#ifndef START_BACKGROUND_THREAD_IN_ASAN_INTERNAL
+static bool UNUSED __local_asan_dyninit = [] {
+ MaybeStartBackgroudThread();
+ SetSoftRssLimitExceededCallback(AsanSoftRssLimitExceededCallback);
+
+ return false;
+}();
+#endif
+
static void AsanInitInternal() {
if (LIKELY(asan_inited)) return;
SanitizerToolName = "AddressSanitizer";
@@ -396,6 +409,14 @@ static void AsanInitInternal() {
// initialization steps look at flags().
InitializeFlags();
+ // Stop performing init at this point if we are being loaded via
+ // dlopen() and the platform supports it.
+ if (SANITIZER_SUPPORTS_INIT_FOR_DLOPEN && UNLIKELY(HandleDlopenInit())) {
+ asan_init_is_running = false;
+ VReport(1, "AddressSanitizer init is being performed for dlopen().\n");
+ return;
+ }
+
AsanCheckIncompatibleRT();
AsanCheckDynamicRTPrereqs();
AvoidCVE_2016_2143();
@@ -420,6 +441,8 @@ static void AsanInitInternal() {
__asan_option_detect_stack_use_after_return =
flags()->detect_stack_use_after_return;
+ __sanitizer::InitializePlatformEarly();
+
// Re-exec ourselves if we need to set additional env or command line args.
MaybeReexec();
@@ -447,8 +470,10 @@ static void AsanInitInternal() {
allocator_options.SetFrom(flags(), common_flags());
InitializeAllocator(allocator_options);
+#ifdef START_BACKGROUND_THREAD_IN_ASAN_INTERNAL
MaybeStartBackgroudThread();
SetSoftRssLimitExceededCallback(AsanSoftRssLimitExceededCallback);
+#endif
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
// should be set to 1 prior to initializing the threads.
diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index faf423d305b7..0895e4ce0d93 100644
--- a/lib/asan/asan_thread.cc
+++ b/lib/asan/asan_thread.cc
@@ -223,9 +223,11 @@ void AsanThread::Init(const InitOptions *options) {
atomic_store(&stack_switching_, false, memory_order_release);
CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls(options);
- CHECK_GT(this->stack_size(), 0U);
- CHECK(AddrIsInMem(stack_bottom_));
- CHECK(AddrIsInMem(stack_top_ - 1));
+ if (stack_top_ != stack_bottom_) {
+ CHECK_GT(this->stack_size(), 0U);
+ CHECK(AddrIsInMem(stack_bottom_));
+ CHECK(AddrIsInMem(stack_top_ - 1));
+ }
ClearShadowForThreadStackAndTLS();
fake_stack_ = nullptr;
if (__asan_option_detect_stack_use_after_return)
@@ -289,20 +291,23 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
DCHECK_EQ(options, nullptr);
uptr tls_size = 0;
uptr stack_size = 0;
- GetThreadStackAndTls(tid() == 0, const_cast<uptr *>(&stack_bottom_),
- const_cast<uptr *>(&stack_size), &tls_begin_, &tls_size);
+ GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
+ &tls_size);
stack_top_ = stack_bottom_ + stack_size;
tls_end_ = tls_begin_ + tls_size;
dtls_ = DTLS_Get();
- int local;
- CHECK(AddrIsInStack((uptr)&local));
+ if (stack_top_ != stack_bottom_) {
+ int local;
+ CHECK(AddrIsInStack((uptr)&local));
+ }
}
#endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
void AsanThread::ClearShadowForThreadStackAndTLS() {
- PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
+ if (stack_top_ != stack_bottom_)
+ PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
if (tls_begin_ != tls_end_) {
uptr tls_begin_aligned = RoundDownTo(tls_begin_, SHADOW_GRANULARITY);
uptr tls_end_aligned = RoundUpTo(tls_end_, SHADOW_GRANULARITY);
@@ -314,6 +319,9 @@ void AsanThread::ClearShadowForThreadStackAndTLS() {
bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
StackFrameAccess *access) {
+ if (stack_top_ == stack_bottom_)
+ return false;
+
uptr bottom = 0;
if (AddrIsInStack(addr)) {
bottom = stack_bottom();
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index 67125d38ad4a..068f4a5d247d 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -159,6 +159,14 @@ INTERCEPTOR_WINAPI(DWORD, CreateThread,
namespace __asan {
void InitializePlatformInterceptors() {
+ // The interceptors were not designed to be removable, so we have to keep this
+ // module alive for the life of the process.
+ HMODULE pinned;
+ CHECK(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+ GET_MODULE_HANDLE_EX_FLAG_PIN,
+ (LPCWSTR)&InitializePlatformInterceptors,
+ &pinned));
+
ASAN_INTERCEPT_FUNC(CreateThread);
ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter);
@@ -314,6 +322,13 @@ int __asan_set_seh_filter() {
return 0;
}
+bool HandleDlopenInit() {
+ // Not supported on this platform.
+ static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+ "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+ return false;
+}
+
#if !ASAN_DYNAMIC
// The CRT runs initializers in this order:
// - C initializers, from XIA to XIZ
diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc
index c6a313d24026..df593ab92de6 100644
--- a/lib/asan/asan_win_dll_thunk.cc
+++ b/lib/asan/asan_win_dll_thunk.cc
@@ -48,6 +48,7 @@ INTERCEPT_WRAP_W_WWW(_recalloc)
INTERCEPT_WRAP_W_WWW(_recalloc_base)
INTERCEPT_WRAP_W_W(_msize)
+INTERCEPT_WRAP_W_W(_msize_base)
INTERCEPT_WRAP_W_W(_expand)
INTERCEPT_WRAP_W_W(_expand_dbg)
diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py
index 68b6f093b533..2dbb05283c1e 100755
--- a/lib/asan/scripts/asan_symbolize.py
+++ b/lib/asan/scripts/asan_symbolize.py
@@ -231,6 +231,10 @@ class DarwinSymbolizer(Symbolizer):
"""Overrides Symbolizer.symbolize."""
if self.binary != binary:
return None
+ if not os.path.exists(binary):
+ # If the binary doesn't exist atos will exit which will lead to IOError
+ # exceptions being raised later on so just don't try to symbolize.
+ return ['{} ({}:{}+{})'.format(addr, binary, self.arch, offset)]
atos_line = self.atos.convert('0x%x' % int(offset, 16))
while "got symbolicator for" in atos_line:
atos_line = self.atos.readline()
@@ -473,7 +477,7 @@ class SymbolizationLoop(object):
symbolized_line = self.symbolize_address(addr, binary, offset, arch)
if not symbolized_line:
if original_binary != binary:
- symbolized_line = self.symbolize_address(addr, binary, offset, arch)
+ symbolized_line = self.symbolize_address(addr, original_binary, offset, arch)
return self.get_symbolized_lines(symbolized_line)
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index 1b7060591530..9e640d1d8b01 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -68,11 +68,6 @@ if(APPLE)
list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS})
endif()
-if(MSVC)
- # Disable exceptions on Windows until they work reliably.
- list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -fno-exceptions -DGTEST_HAS_SEH=0)
-endif()
-
set(ASAN_BLACKLIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/asan_test.ignore")
set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS
${ASAN_UNITTEST_COMMON_CFLAGS}
diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc
index 69c8fe6f4818..b5c8303cb84b 100644
--- a/lib/asan/tests/asan_interface_test.cc
+++ b/lib/asan/tests/asan_interface_test.cc
@@ -102,6 +102,7 @@ TEST(AddressSanitizerInterface, GetHeapSizeTest) {
}
}
+#if !defined(__NetBSD__)
static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
static const size_t kManyThreadsIterations = 250;
static const size_t kManyThreadsNumThreads =
@@ -135,6 +136,7 @@ TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
// so we can't check for equality here.
EXPECT_LT(after_test, before_test + (1UL<<20));
}
+#endif
static void DoDoubleFree() {
int *x = Ident(new int);
diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc
index 65acb2839ba1..3e366842c65f 100644
--- a/lib/asan/tests/asan_noinst_test.cc
+++ b/lib/asan/tests/asan_noinst_test.cc
@@ -153,6 +153,7 @@ TEST(AddressSanitizer, QuarantineTest) {
EXPECT_LT(i, max_i);
}
+#if !defined(__NetBSD__)
void *ThreadedQuarantineTestWorker(void *unused) {
(void)unused;
u32 seed = my_rand();
@@ -187,6 +188,7 @@ TEST(AddressSanitizer, ThreadedQuarantineTest) {
EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20));
}
}
+#endif
void *ThreadedOneSizeMallocStress(void *unused) {
(void)unused;
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 25d6a2083450..464e99f614d5 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -1295,6 +1295,7 @@ TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
}
}
+#if !defined(__NetBSD__) && !defined(__i386__)
// https://github.com/google/sanitizers/issues/66
TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
for (int i = 0; i < 1000000; i++) {
@@ -1304,6 +1305,7 @@ TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
EXPECT_DEATH(x[Ident(8192)] = 0, "AddressSanitizer: heap-buffer-overflow");
delete [] Ident(x);
}
+#endif
// Test that instrumentation of stack allocations takes into account
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
index 82332967b104..77947417bfed 100644
--- a/lib/builtins/CMakeLists.txt
+++ b/lib/builtins/CMakeLists.txt
@@ -505,7 +505,9 @@ set(mips64el_SOURCES ${GENERIC_TF_SOURCES}
set(powerpc64_SOURCES
ppc/divtc3.c
ppc/fixtfdi.c
+ ppc/fixunstfti.c
ppc/fixunstfdi.c
+ ppc/floattitf.c
ppc/floatditf.c
ppc/floatunditf.c
ppc/gcc_qadd.c
diff --git a/lib/builtins/Darwin-excludes/10.4.txt b/lib/builtins/Darwin-excludes/10.4.txt
deleted file mode 100644
index 603c0b3bf399..000000000000
--- a/lib/builtins/Darwin-excludes/10.4.txt
+++ /dev/null
@@ -1,137 +0,0 @@
-absvdi2
-absvsi2
-absvti2
-adddf3
-addsf3
-addtf3
-addvdi3
-addvsi3
-addvti3
-apple_versioning
-ashldi3
-ashlti3
-ashrdi3
-ashrti3
-atomic_flag_clear
-atomic_flag_clear_explicit
-atomic_flag_test_and_set
-atomic_flag_test_and_set_explicit
-atomic_signal_fence
-atomic_thread_fence
-clear_cache
-clzdi2
-clzsi2
-clzti2
-cmpdi2
-cmpti2
-comparedf2
-comparesf2
-ctzdi2
-ctzsi2
-ctzti2
-divdc3
-divdf3
-divdi3
-divmoddi4
-divmodsi4
-divsc3
-divsf3
-divsi3
-divtf3
-divti3
-divxc3
-enable_execute_stack
-extendhfsf2
-extendsfdf2
-ffsdi2
-ffsti2
-fixdfdi
-fixdfsi
-fixdfti
-fixsfdi
-fixsfsi
-fixsfti
-fixunsdfdi
-fixunsdfsi
-fixunsdfti
-fixunssfdi
-fixunssfsi
-fixunssfti
-fixunsxfdi
-fixunsxfsi
-fixunsxfti
-fixxfdi
-fixxfti
-floatdidf
-floatdisf
-floatdixf
-floatsidf
-floatsisf
-floattidf
-floattisf
-floattixf
-floatunsidf
-floatunsisf
-floatuntidf
-floatuntisf
-floatuntixf
-gcc_personality_v0
-gnu_f2h_ieee
-gnu_h2f_ieee
-lshrdi3
-lshrti3
-moddi3
-modsi3
-modti3
-muldc3
-muldf3
-muldi3
-mulodi4
-mulosi4
-muloti4
-mulsc3
-mulsf3
-multf3
-multi3
-mulvdi3
-mulvsi3
-mulvti3
-mulxc3
-negdf2
-negdi2
-negsf2
-negti2
-negvdi2
-negvsi2
-negvti2
-paritydi2
-paritysi2
-parityti2
-popcountdi2
-popcountsi2
-popcountti2
-powidf2
-powisf2
-powitf2
-powixf2
-subdf3
-subsf3
-subtf3
-subvdi3
-subvsi3
-subvti3
-trampoline_setup
-truncdfhf2
-truncdfsf2
-truncsfhf2
-ucmpdi2
-ucmpti2
-udivdi3
-udivmoddi4
-udivmodsi4
-udivmodti4
-udivsi3
-udivti3
-umoddi3
-umodsi3
-umodti3
diff --git a/lib/builtins/arm/addsf3.S b/lib/builtins/arm/addsf3.S
index 362b5c147ea6..74723cbeff74 100644
--- a/lib/builtins/arm/addsf3.S
+++ b/lib/builtins/arm/addsf3.S
@@ -178,7 +178,7 @@ LOCAL_LABEL(do_substraction):
push {r0, r1, r2, r3}
movs r0, r4
- bl __clzsi2
+ bl SYMBOL_NAME(__clzsi2)
movs r5, r0
pop {r0, r1, r2, r3}
// shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
diff --git a/lib/builtins/arm/aeabi_cdcmp.S b/lib/builtins/arm/aeabi_cdcmp.S
index 87dd03dce94d..adc2d55d90f5 100644
--- a/lib/builtins/arm/aeabi_cdcmp.S
+++ b/lib/builtins/arm/aeabi_cdcmp.S
@@ -55,7 +55,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
mov ip, #APSR_C
msr APSR_nzcvq, ip
#else
- msr CPSR_f, #APSR_C
+ msr APSR_nzcvq, #APSR_C
#endif
JMP(lr)
#endif
@@ -115,11 +115,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple)
movne ip, #(APSR_C)
1:
-#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
msr APSR_nzcvq, ip
-#else
- msr CPSR_f, ip
-#endif
pop {r0-r3}
POP_PC()
#endif
diff --git a/lib/builtins/arm/aeabi_cfcmp.S b/lib/builtins/arm/aeabi_cfcmp.S
index c5fee6b6a08e..4b1de997687f 100644
--- a/lib/builtins/arm/aeabi_cfcmp.S
+++ b/lib/builtins/arm/aeabi_cfcmp.S
@@ -55,7 +55,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
mov ip, #APSR_C
msr APSR_nzcvq, ip
#else
- msr CPSR_f, #APSR_C
+ msr APSR_nzcvq, #APSR_C
#endif
JMP(lr)
#endif
@@ -115,11 +115,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple)
movne ip, #(APSR_C)
1:
-#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
msr APSR_nzcvq, ip
-#else
- msr CPSR_f, ip
-#endif
pop {r0-r3}
POP_PC()
#endif
diff --git a/lib/builtins/clzdi2.c b/lib/builtins/clzdi2.c
index b56d98f5c01f..1819e6be436b 100644
--- a/lib/builtins/clzdi2.c
+++ b/lib/builtins/clzdi2.c
@@ -16,8 +16,13 @@
/* Returns: the number of leading 0-bits */
-#if !defined(__clang__) && (defined(__sparc64__) || defined(__mips64) || defined(__riscv__))
-/* gcc resolves __builtin_clz -> __clzdi2 leading to infinite recursion */
+#if !defined(__clang__) && \
+ ((defined(__sparc__) && defined(__arch64__)) || \
+ defined(__mips64) || \
+ (defined(__riscv) && __SIZEOF_POINTER__ >= 8))
+/* On 64-bit architectures with neither a native clz instruction nor a native
+ * ctz instruction, gcc resolves __builtin_clz to __clzdi2 rather than
+ * __clzsi2, leading to infinite recursion. */
#define __builtin_clz(a) __clzsi2(a)
extern si_int __clzsi2(si_int);
#endif
diff --git a/lib/builtins/cpu_model.c b/lib/builtins/cpu_model.c
index 43b913390fc4..fb2b899fc70a 100644
--- a/lib/builtins/cpu_model.c
+++ b/lib/builtins/cpu_model.c
@@ -55,6 +55,9 @@ enum ProcessorTypes {
AMD_BTVER2,
AMDFAM17H,
INTEL_KNM,
+ INTEL_GOLDMONT,
+ INTEL_GOLDMONT_PLUS,
+ INTEL_TREMONT,
CPU_TYPE_MAX
};
@@ -76,6 +79,8 @@ enum ProcessorSubtypes {
INTEL_COREI7_SKYLAKE,
INTEL_COREI7_SKYLAKE_AVX512,
INTEL_COREI7_CANNONLAKE,
+ INTEL_COREI7_ICELAKE_CLIENT,
+ INTEL_COREI7_ICELAKE_SERVER,
CPU_SUBTYPE_MAX
};
@@ -110,7 +115,12 @@ enum ProcessorFeatures {
FEATURE_AVX512IFMA,
FEATURE_AVX5124VNNIW,
FEATURE_AVX5124FMAPS,
- FEATURE_AVX512VPOPCNTDQ
+ FEATURE_AVX512VPOPCNTDQ,
+ FEATURE_AVX512VBMI2,
+ FEATURE_GFNI,
+ FEATURE_VPCLMULQDQ,
+ FEATURE_AVX512VNNI,
+ FEATURE_AVX512BITALG
};
// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).
@@ -364,6 +374,14 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
case 0x4c: // really airmont
*Type = INTEL_SILVERMONT;
break; // "silvermont"
+ // Goldmont:
+ case 0x5c: // Apollo Lake
+ case 0x5f: // Denverton
+ *Type = INTEL_GOLDMONT;
+ break; // "goldmont"
+ case 0x7a:
+ *Type = INTEL_GOLDMONT_PLUS;
+ break;
case 0x57:
*Type = INTEL_KNL; // knl
@@ -438,35 +456,45 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
}
static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
- unsigned *FeaturesOut) {
+ unsigned *FeaturesOut,
+ unsigned *Features2Out) {
unsigned Features = 0;
+ unsigned Features2 = 0;
unsigned EAX, EBX;
+#define setFeature(F) \
+ do { \
+ if (F < 32) \
+ Features |= 1U << (F & 0x1f); \
+ else if (F < 64) \
+ Features2 |= 1U << ((F - 32) & 0x1f); \
+ } while (0)
+
if ((EDX >> 15) & 1)
- Features |= 1 << FEATURE_CMOV;
+ setFeature(FEATURE_CMOV);
if ((EDX >> 23) & 1)
- Features |= 1 << FEATURE_MMX;
+ setFeature(FEATURE_MMX);
if ((EDX >> 25) & 1)
- Features |= 1 << FEATURE_SSE;
+ setFeature(FEATURE_SSE);
if ((EDX >> 26) & 1)
- Features |= 1 << FEATURE_SSE2;
+ setFeature(FEATURE_SSE2);
if ((ECX >> 0) & 1)
- Features |= 1 << FEATURE_SSE3;
+ setFeature(FEATURE_SSE3);
if ((ECX >> 1) & 1)
- Features |= 1 << FEATURE_PCLMUL;
+ setFeature(FEATURE_PCLMUL);
if ((ECX >> 9) & 1)
- Features |= 1 << FEATURE_SSSE3;
+ setFeature(FEATURE_SSSE3);
if ((ECX >> 12) & 1)
- Features |= 1 << FEATURE_FMA;
+ setFeature(FEATURE_FMA);
if ((ECX >> 19) & 1)
- Features |= 1 << FEATURE_SSE4_1;
+ setFeature(FEATURE_SSE4_1);
if ((ECX >> 20) & 1)
- Features |= 1 << FEATURE_SSE4_2;
+ setFeature(FEATURE_SSE4_2);
if ((ECX >> 23) & 1)
- Features |= 1 << FEATURE_POPCNT;
+ setFeature(FEATURE_POPCNT);
if ((ECX >> 25) & 1)
- Features |= 1 << FEATURE_AES;
+ setFeature(FEATURE_AES);
// If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV
// indicates that the AVX registers will be saved and restored on context
@@ -477,43 +505,53 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0);
if (HasAVX)
- Features |= 1 << FEATURE_AVX;
+ setFeature(FEATURE_AVX);
bool HasLeaf7 =
MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);
if (HasLeaf7 && ((EBX >> 3) & 1))
- Features |= 1 << FEATURE_BMI;
+ setFeature(FEATURE_BMI);
if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX)
- Features |= 1 << FEATURE_AVX2;
+ setFeature(FEATURE_AVX2);
if (HasLeaf7 && ((EBX >> 9) & 1))
- Features |= 1 << FEATURE_BMI2;
+ setFeature(FEATURE_BMI2);
if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX512F;
+ setFeature(FEATURE_AVX512F);
if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX512DQ;
+ setFeature(FEATURE_AVX512DQ);
if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX512IFMA;
+ setFeature(FEATURE_AVX512IFMA);
if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX512PF;
+ setFeature(FEATURE_AVX512PF);
if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX512ER;
+ setFeature(FEATURE_AVX512ER);
if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX512CD;
+ setFeature(FEATURE_AVX512CD);
if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX512BW;
+ setFeature(FEATURE_AVX512BW);
if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX512VL;
+ setFeature(FEATURE_AVX512VL);
if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX512VBMI;
+ setFeature(FEATURE_AVX512VBMI);
+ if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512VBMI2);
+ if (HasLeaf7 && ((ECX >> 8) & 1))
+ setFeature(FEATURE_GFNI);
+ if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVX)
+ setFeature(FEATURE_VPCLMULQDQ);
+ if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512VNNI);
+ if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512BITALG);
if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX512VPOPCNTDQ;
+ setFeature(FEATURE_AVX512VPOPCNTDQ);
if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX5124VNNIW;
+ setFeature(FEATURE_AVX5124VNNIW);
if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save)
- Features |= 1 << FEATURE_AVX5124FMAPS;
+ setFeature(FEATURE_AVX5124FMAPS);
unsigned MaxExtLevel;
getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX);
@@ -521,13 +559,15 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 &&
!getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
if (HasExtLeaf1 && ((ECX >> 6) & 1))
- Features |= 1 << FEATURE_SSE4_A;
+ setFeature(FEATURE_SSE4_A);
if (HasExtLeaf1 && ((ECX >> 11) & 1))
- Features |= 1 << FEATURE_XOP;
+ setFeature(FEATURE_XOP);
if (HasExtLeaf1 && ((ECX >> 16) & 1))
- Features |= 1 << FEATURE_FMA4;
+ setFeature(FEATURE_FMA4);
*FeaturesOut = Features;
+ *Features2Out = Features2;
+#undef setFeature
}
#if defined(HAVE_INIT_PRIORITY)
@@ -548,8 +588,9 @@ struct __processor_model {
unsigned int __cpu_subtype;
unsigned int __cpu_features[1];
} __cpu_model = {0, 0, 0, {0}};
+unsigned int __cpu_features2;
-/* A constructor function that is sets __cpu_model and __cpu_features with
+/* A constructor function that is sets __cpu_model and __cpu_features2 with
the right values. This needs to run only once. This constructor is
given the highest priority and it should run before constructors without
the priority set. However, it still runs after ifunc initializers and
@@ -562,6 +603,7 @@ __cpu_indicator_init(void) {
unsigned Vendor;
unsigned Model, Family, Brand_id;
unsigned Features = 0;
+ unsigned Features2 = 0;
/* This function needs to run just once. */
if (__cpu_model.__cpu_vendor)
@@ -580,8 +622,9 @@ __cpu_indicator_init(void) {
Brand_id = EBX & 0xff;
/* Find available features. */
- getAvailableFeatures(ECX, EDX, MaxLeaf, &Features);
+ getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2);
__cpu_model.__cpu_features[0] = Features;
+ __cpu_features2 = Features2;
if (Vendor == SIG_INTEL) {
/* Get CPU type. */
diff --git a/lib/builtins/ctzdi2.c b/lib/builtins/ctzdi2.c
index eecde29718d7..ef6d7fea1365 100644
--- a/lib/builtins/ctzdi2.c
+++ b/lib/builtins/ctzdi2.c
@@ -16,8 +16,13 @@
/* Returns: the number of trailing 0-bits */
-#if !defined(__clang__) && (defined(__sparc64__) || defined(__mips64) || defined(__riscv__))
-/* gcc resolves __builtin_ctz -> __ctzdi2 leading to infinite recursion */
+#if !defined(__clang__) && \
+ ((defined(__sparc__) && defined(__arch64__)) || \
+ defined(__mips64) || \
+ (defined(__riscv) && __SIZEOF_POINTER__ >= 8))
+/* On 64-bit architectures with neither a native clz instruction nor a native
+ * ctz instruction, gcc resolves __builtin_ctz to __ctzdi2 rather than
+ * __ctzsi2, leading to infinite recursion. */
#define __builtin_ctz(a) __ctzsi2(a)
extern si_int __ctzsi2(si_int);
#endif
diff --git a/lib/builtins/divdc3.c b/lib/builtins/divdc3.c
index 3c88390b5e77..392d6ecacde1 100644
--- a/lib/builtins/divdc3.c
+++ b/lib/builtins/divdc3.c
@@ -12,6 +12,8 @@
* ===----------------------------------------------------------------------===
*/
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
#include "int_lib.h"
#include "int_math.h"
@@ -21,7 +23,7 @@ COMPILER_RT_ABI Dcomplex
__divdc3(double __a, double __b, double __c, double __d)
{
int __ilogbw = 0;
- double __logbw = crt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d)));
+ double __logbw = __compiler_rt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d)));
if (crt_isfinite(__logbw))
{
__ilogbw = (int)__logbw;
diff --git a/lib/builtins/divdf3.c b/lib/builtins/divdf3.c
index 04a4dc5571ca..411c82ebb87a 100644
--- a/lib/builtins/divdf3.c
+++ b/lib/builtins/divdf3.c
@@ -21,36 +21,36 @@
COMPILER_RT_ABI fp_t
__divdf3(fp_t a, fp_t b) {
-
+
const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-
+
rep_t aSignificand = toRep(a) & significandMask;
rep_t bSignificand = toRep(b) & significandMask;
int scale = 0;
-
+
// Detect if a or b is zero, denormal, infinity, or NaN.
if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
+
const rep_t aAbs = toRep(a) & absMask;
const rep_t bAbs = toRep(b) & absMask;
-
+
// NaN / anything = qNaN
if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
// anything / NaN = qNaN
if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
+
if (aAbs == infRep) {
// infinity / infinity = NaN
if (bAbs == infRep) return fromRep(qnanRep);
// infinity / anything else = +/- infinity
else return fromRep(aAbs | quotientSign);
}
-
+
// anything else / infinity = +/- 0
if (bAbs == infRep) return fromRep(quotientSign);
-
+
if (!aAbs) {
// zero / zero = NaN
if (!bAbs) return fromRep(qnanRep);
@@ -59,28 +59,28 @@ __divdf3(fp_t a, fp_t b) {
}
// anything else / zero = +/- infinity
if (!bAbs) return fromRep(infRep | quotientSign);
-
+
// one or both of a or b is denormal, the other (if applicable) is a
// normal number. Renormalize one or both of a and b, and set scale to
// include the necessary exponent adjustment.
if (aAbs < implicitBit) scale += normalize(&aSignificand);
if (bAbs < implicitBit) scale -= normalize(&bSignificand);
}
-
+
// Or in the implicit significand bit. (If we fell through from the
// denormal path it was already set by normalize( ), but setting it twice
// won't hurt anything.)
aSignificand |= implicitBit;
bSignificand |= implicitBit;
int quotientExponent = aExponent - bExponent + scale;
-
+
// Align the significand of b as a Q31 fixed-point number in the range
// [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
// polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
// is accurate to about 3.5 binary digits.
const uint32_t q31b = bSignificand >> 21;
uint32_t recip32 = UINT32_C(0x7504f333) - q31b;
-
+
// Now refine the reciprocal estimate using a Newton-Raphson iteration:
//
// x1 = x0 * (2 - x0 * b)
@@ -95,13 +95,13 @@ __divdf3(fp_t a, fp_t b) {
recip32 = (uint64_t)recip32 * correction32 >> 31;
correction32 = -((uint64_t)recip32 * q31b >> 32);
recip32 = (uint64_t)recip32 * correction32 >> 31;
-
+
// recip32 might have overflowed to exactly zero in the preceding
// computation if the high word of b is exactly 1.0. This would sabotage
// the full-width final stage of the computation that follows, so we adjust
// recip32 downward by one bit.
recip32--;
-
+
// We need to perform one more iteration to get us to 56 binary digits;
// The last iteration needs to happen with extra precision.
const uint32_t q63blo = bSignificand << 11;
@@ -110,14 +110,14 @@ __divdf3(fp_t a, fp_t b) {
uint32_t cHi = correction >> 32;
uint32_t cLo = correction;
reciprocal = (uint64_t)recip32*cHi + ((uint64_t)recip32*cLo >> 32);
-
+
// We already adjusted the 32-bit estimate, now we need to adjust the final
// 64-bit reciprocal estimate downward to ensure that it is strictly smaller
// than the infinitely precise exact reciprocal. Because the computation
// of the Newton-Raphson step is truncating at every step, this adjustment
// is small; most of the work is already done.
reciprocal -= 2;
-
+
// The numerical reciprocal is accurate to within 2^-56, lies in the
// interval [0.5, 1.0), and is strictly smaller than the true reciprocal
// of b. Multiplying a by this reciprocal thus gives a numerical q = a/b
@@ -127,12 +127,12 @@ __divdf3(fp_t a, fp_t b) {
// 2. q is in the interval [0.5, 2.0)
// 3. the error in q is bounded away from 2^-53 (actually, we have a
// couple of bits to spare, but this is all we need).
-
+
// We need a 64 x 64 multiply high to compute q, which isn't a basic
// operation in C, so we need to be a little bit fussy.
rep_t quotient, quotientLo;
wideMultiply(aSignificand << 2, reciprocal, &quotient, &quotientLo);
-
+
// Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
// In either case, we are going to compute a residual of the form
//
@@ -141,7 +141,7 @@ __divdf3(fp_t a, fp_t b) {
// We know from the construction of q that r satisfies:
//
// 0 <= r < ulp(q)*b
- //
+ //
// if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
// already have the correct result. The exact halfway case cannot occur.
// We also take this time to right shift quotient if it falls in the [1,2)
@@ -154,20 +154,20 @@ __divdf3(fp_t a, fp_t b) {
quotient >>= 1;
residual = (aSignificand << 52) - quotient * bSignificand;
}
-
+
const int writtenExponent = quotientExponent + exponentBias;
-
+
if (writtenExponent >= maxExponent) {
// If we have overflowed the exponent, return infinity.
return fromRep(infRep | quotientSign);
}
-
+
else if (writtenExponent < 1) {
// Flush denormals to zero. In the future, it would be nice to add
// code to round them correctly.
return fromRep(quotientSign);
}
-
+
else {
const bool round = (residual << 1) > bSignificand;
// Clear the implicit bit
diff --git a/lib/builtins/divsc3.c b/lib/builtins/divsc3.c
index 42a48315e66d..0d18a256c3de 100644
--- a/lib/builtins/divsc3.c
+++ b/lib/builtins/divsc3.c
@@ -12,6 +12,8 @@
*===----------------------------------------------------------------------===
*/
+#define SINGLE_PRECISION
+#include "fp_lib.h"
#include "int_lib.h"
#include "int_math.h"
@@ -21,7 +23,8 @@ COMPILER_RT_ABI Fcomplex
__divsc3(float __a, float __b, float __c, float __d)
{
int __ilogbw = 0;
- float __logbw = crt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
+ float __logbw =
+ __compiler_rt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
if (crt_isfinite(__logbw))
{
__ilogbw = (int)__logbw;
diff --git a/lib/builtins/divsf3.c b/lib/builtins/divsf3.c
index 65294d70fc61..a74917fd1de5 100644
--- a/lib/builtins/divsf3.c
+++ b/lib/builtins/divsf3.c
@@ -21,36 +21,36 @@
COMPILER_RT_ABI fp_t
__divsf3(fp_t a, fp_t b) {
-
+
const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-
+
rep_t aSignificand = toRep(a) & significandMask;
rep_t bSignificand = toRep(b) & significandMask;
int scale = 0;
-
+
// Detect if a or b is zero, denormal, infinity, or NaN.
if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
+
const rep_t aAbs = toRep(a) & absMask;
const rep_t bAbs = toRep(b) & absMask;
-
+
// NaN / anything = qNaN
if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
// anything / NaN = qNaN
if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
+
if (aAbs == infRep) {
// infinity / infinity = NaN
if (bAbs == infRep) return fromRep(qnanRep);
// infinity / anything else = +/- infinity
else return fromRep(aAbs | quotientSign);
}
-
+
// anything else / infinity = +/- 0
if (bAbs == infRep) return fromRep(quotientSign);
-
+
if (!aAbs) {
// zero / zero = NaN
if (!bAbs) return fromRep(qnanRep);
@@ -59,28 +59,28 @@ __divsf3(fp_t a, fp_t b) {
}
// anything else / zero = +/- infinity
if (!bAbs) return fromRep(infRep | quotientSign);
-
+
// one or both of a or b is denormal, the other (if applicable) is a
// normal number. Renormalize one or both of a and b, and set scale to
// include the necessary exponent adjustment.
if (aAbs < implicitBit) scale += normalize(&aSignificand);
if (bAbs < implicitBit) scale -= normalize(&bSignificand);
}
-
+
// Or in the implicit significand bit. (If we fell through from the
// denormal path it was already set by normalize( ), but setting it twice
// won't hurt anything.)
aSignificand |= implicitBit;
bSignificand |= implicitBit;
int quotientExponent = aExponent - bExponent + scale;
-
+
// Align the significand of b as a Q31 fixed-point number in the range
// [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
// polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
// is accurate to about 3.5 binary digits.
uint32_t q31b = bSignificand << 8;
uint32_t reciprocal = UINT32_C(0x7504f333) - q31b;
-
+
// Now refine the reciprocal estimate using a Newton-Raphson iteration:
//
// x1 = x0 * (2 - x0 * b)
@@ -95,7 +95,7 @@ __divsf3(fp_t a, fp_t b) {
reciprocal = (uint64_t)reciprocal * correction >> 31;
correction = -((uint64_t)reciprocal * q31b >> 32);
reciprocal = (uint64_t)reciprocal * correction >> 31;
-
+
// Exhaustive testing shows that the error in reciprocal after three steps
// is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our
// expectations. We bump the reciprocal by a tiny value to force the error
@@ -103,7 +103,7 @@ __divsf3(fp_t a, fp_t b) {
// be specific). This also causes 1/1 to give a sensible approximation
// instead of zero (due to overflow).
reciprocal -= 2;
-
+
// The numerical reciprocal is accurate to within 2^-28, lies in the
// interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller
// than the true reciprocal of b. Multiplying a by this reciprocal thus
@@ -115,9 +115,9 @@ __divsf3(fp_t a, fp_t b) {
// from the fact that we truncate the product, and the 2^27 term
// is the error in the reciprocal of b scaled by the maximum
// possible value of a. As a consequence of this error bound,
- // either q or nextafter(q) is the correctly rounded
+ // either q or nextafter(q) is the correctly rounded
rep_t quotient = (uint64_t)reciprocal*(aSignificand << 1) >> 32;
-
+
// Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
// In either case, we are going to compute a residual of the form
//
@@ -126,7 +126,7 @@ __divsf3(fp_t a, fp_t b) {
// We know from the construction of q that r satisfies:
//
// 0 <= r < ulp(q)*b
- //
+ //
// if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
// already have the correct result. The exact halfway case cannot occur.
// We also take this time to right shift quotient if it falls in the [1,2)
@@ -141,18 +141,18 @@ __divsf3(fp_t a, fp_t b) {
}
const int writtenExponent = quotientExponent + exponentBias;
-
+
if (writtenExponent >= maxExponent) {
// If we have overflowed the exponent, return infinity.
return fromRep(infRep | quotientSign);
}
-
+
else if (writtenExponent < 1) {
// Flush denormals to zero. In the future, it would be nice to add
// code to round them correctly.
return fromRep(quotientSign);
}
-
+
else {
const bool round = (residual << 1) > bSignificand;
// Clear the implicit bit
diff --git a/lib/builtins/divtc3.c b/lib/builtins/divtc3.c
index 16e538ba4a33..e5ea00d841e3 100644
--- a/lib/builtins/divtc3.c
+++ b/lib/builtins/divtc3.c
@@ -12,6 +12,8 @@
*===----------------------------------------------------------------------===
*/
+#define QUAD_PRECISION
+#include "fp_lib.h"
#include "int_lib.h"
#include "int_math.h"
@@ -21,7 +23,8 @@ COMPILER_RT_ABI Lcomplex
__divtc3(long double __a, long double __b, long double __c, long double __d)
{
int __ilogbw = 0;
- long double __logbw = crt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
+ long double __logbw =
+ __compiler_rt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
if (crt_isfinite(__logbw))
{
__ilogbw = (int)__logbw;
diff --git a/lib/builtins/emutls.c b/lib/builtins/emutls.c
index 07d436e267d8..ef95a1c260c1 100644
--- a/lib/builtins/emutls.c
+++ b/lib/builtins/emutls.c
@@ -42,6 +42,7 @@ static void emutls_shutdown(emutls_address_array *array);
static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t emutls_pthread_key;
+static bool emutls_key_created = false;
typedef unsigned int gcc_word __attribute__((mode(word)));
typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
@@ -109,6 +110,7 @@ static void emutls_key_destructor(void* ptr) {
static __inline void emutls_init(void) {
if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
abort();
+ emutls_key_created = true;
}
static __inline void emutls_init_once(void) {
@@ -390,3 +392,14 @@ void* __emutls_get_address(__emutls_control* control) {
array->data[index] = emutls_allocate_object(control);
return array->data[index];
}
+
+#ifdef __BIONIC__
+/* Called by Bionic on dlclose to delete the emutls pthread key. */
+__attribute__((visibility("hidden")))
+void __emutls_unregister_key(void) {
+ if (emutls_key_created) {
+ pthread_key_delete(emutls_pthread_key);
+ emutls_key_created = false;
+ }
+}
+#endif
diff --git a/lib/builtins/fp_lib.h b/lib/builtins/fp_lib.h
index 223fb980aaed..a0e19ab6a8f6 100644
--- a/lib/builtins/fp_lib.h
+++ b/lib/builtins/fp_lib.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include <limits.h>
#include "int_lib.h"
+#include "int_math.h"
// x86_64 FreeBSD prior v9.3 define fixed-width types incorrectly in
// 32-bit mode.
@@ -265,6 +266,62 @@ static __inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, unsigned int
*hi = 0;
}
}
+
+// Implements logb methods (logb, logbf, logbl) for IEEE-754. This avoids
+// pulling in a libm dependency from compiler-rt, but is not meant to replace
+// it (i.e. code calling logb() should get the one from libm, not this), hence
+// the __compiler_rt prefix.
+static __inline fp_t __compiler_rt_logbX(fp_t x) {
+ rep_t rep = toRep(x);
+ int exp = (rep & exponentMask) >> significandBits;
+
+ // Abnormal cases:
+ // 1) +/- inf returns +inf; NaN returns NaN
+ // 2) 0.0 returns -inf
+ if (exp == maxExponent) {
+ if (((rep & signBit) == 0) || (x != x)) {
+ return x; // NaN or +inf: return x
+ } else {
+ return -x; // -inf: return -x
+ }
+ } else if (x == 0.0) {
+ // 0.0: return -inf
+ return fromRep(infRep | signBit);
+ }
+
+ if (exp != 0) {
+ // Normal number
+ return exp - exponentBias; // Unbias exponent
+ } else {
+ // Subnormal number; normalize and repeat
+ rep &= absMask;
+ const int shift = 1 - normalize(&rep);
+ exp = (rep & exponentMask) >> significandBits;
+ return exp - exponentBias - shift; // Unbias exponent
+ }
+}
+#endif
+
+#if defined(SINGLE_PRECISION)
+static __inline fp_t __compiler_rt_logbf(fp_t x) {
+ return __compiler_rt_logbX(x);
+}
+#elif defined(DOUBLE_PRECISION)
+static __inline fp_t __compiler_rt_logb(fp_t x) {
+ return __compiler_rt_logbX(x);
+}
+#elif defined(QUAD_PRECISION)
+ #if defined(CRT_LDBL_128BIT)
+static __inline fp_t __compiler_rt_logbl(fp_t x) {
+ return __compiler_rt_logbX(x);
+}
+ #else
+// The generic implementation only works for ieee754 floating point. For other
+// floating point types, continue to rely on the libm implementation for now.
+static __inline long double __compiler_rt_logbl(long double x) {
+ return crt_logbl(x);
+}
+ #endif
#endif
#endif // FP_LIB_HEADER
diff --git a/lib/builtins/gcc_personality_v0.c b/lib/builtins/gcc_personality_v0.c
index 0bc765624564..68581ef16434 100644
--- a/lib/builtins/gcc_personality_v0.c
+++ b/lib/builtins/gcc_personality_v0.c
@@ -206,8 +206,8 @@ __gcc_personality_v0(int version, _Unwind_Action actions,
if ( lsda == (uint8_t*) 0 )
return continueUnwind(exceptionObject, context);
- uintptr_t pc = _Unwind_GetIP(context)-1;
- uintptr_t funcStart = _Unwind_GetRegionStart(context);
+ uintptr_t pc = (uintptr_t)_Unwind_GetIP(context)-1;
+ uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
uintptr_t pcOffset = pc - funcStart;
/* Parse LSDA header. */
@@ -249,4 +249,3 @@ __gcc_personality_v0(int version, _Unwind_Action actions,
/* No landing pad found, continue unwinding. */
return continueUnwind(exceptionObject, context);
}
-
diff --git a/lib/builtins/int_lib.h b/lib/builtins/int_lib.h
index 9d09e2dc915b..fe8a3bdedc0e 100644
--- a/lib/builtins/int_lib.h
+++ b/lib/builtins/int_lib.h
@@ -43,7 +43,7 @@
#define AEABI_RTABI __attribute__((__pcs__("aapcs")))
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__clang__)
#define ALWAYS_INLINE __forceinline
#define NOINLINE __declspec(noinline)
#define NORETURN __declspec(noreturn)
diff --git a/lib/builtins/int_math.h b/lib/builtins/int_math.h
index fc81fb7f0220..aa3d0721a8ab 100644
--- a/lib/builtins/int_math.h
+++ b/lib/builtins/int_math.h
@@ -92,12 +92,8 @@
#endif
#if defined(_MSC_VER) && !defined(__clang__)
-#define crt_logb(x) logb((x))
-#define crt_logbf(x) logbf((x))
#define crt_logbl(x) logbl((x))
#else
-#define crt_logb(x) __builtin_logb((x))
-#define crt_logbf(x) __builtin_logbf((x))
#define crt_logbl(x) __builtin_logbl((x))
#endif
diff --git a/lib/builtins/int_types.h b/lib/builtins/int_types.h
index f53f343d35d5..9f8da56cb77b 100644
--- a/lib/builtins/int_types.h
+++ b/lib/builtins/int_types.h
@@ -60,10 +60,19 @@ typedef union
}s;
} udwords;
-#if (defined(__LP64__) || defined(__wasm__) || defined(__mips64)) || defined(__riscv)
+#if defined(__LP64__) || defined(__wasm__) || defined(__mips64) || \
+ defined(__riscv) || defined(_WIN64)
#define CRT_HAS_128BIT
#endif
+/* MSVC doesn't have a working 128bit integer type. Users should really compile
+ * compiler-rt with clang, but if they happen to be doing a standalone build for
+ * asan or something else, disable the 128 bit parts so things sort of work.
+ */
+#if defined(_MSC_VER) && !defined(__clang__)
+#undef CRT_HAS_128BIT
+#endif
+
#ifdef CRT_HAS_128BIT
typedef int ti_int __attribute__ ((mode (TI)));
typedef unsigned tu_int __attribute__ ((mode (TI)));
@@ -137,6 +146,18 @@ typedef struct
#endif /* _YUGA_LITTLE_ENDIAN */
} uqwords;
+/* Check if the target supports 80 bit extended precision long doubles.
+ * Notably, on x86 Windows, MSVC only provides a 64-bit long double, but GCC
+ * still makes it 80 bits. Clang will match whatever compiler it is trying to
+ * be compatible with.
+ */
+#if ((defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)) || \
+ defined(__m68k__) || defined(__ia64__)
+#define HAS_80_BIT_LONG_DOUBLE 1
+#else
+#define HAS_80_BIT_LONG_DOUBLE 0
+#endif
+
typedef union
{
uqwords u;
diff --git a/lib/builtins/int_util.c b/lib/builtins/int_util.c
index de87410dbca2..752f2015580e 100644
--- a/lib/builtins/int_util.c
+++ b/lib/builtins/int_util.c
@@ -27,7 +27,7 @@ NORETURN extern void panic(const char *, ...);
#ifndef _WIN32
__attribute__((visibility("hidden")))
#endif
-void compilerrt_abort_impl(const char *file, int line, const char *function) {
+void __compilerrt_abort_impl(const char *file, int line, const char *function) {
panic("%s:%d: abort in %s", file, line, function);
}
@@ -41,7 +41,7 @@ NORETURN extern void __assert_rtn(const char *func, const char *file, int line,
__attribute__((weak))
__attribute__((visibility("hidden")))
#endif
-void compilerrt_abort_impl(const char *file, int line, const char *function) {
+void __compilerrt_abort_impl(const char *file, int line, const char *function) {
__assert_rtn(function, file, line, "libcompiler_rt abort");
}
@@ -51,7 +51,7 @@ void compilerrt_abort_impl(const char *file, int line, const char *function) {
__attribute__((weak))
__attribute__((visibility("hidden")))
#endif
-void compilerrt_abort_impl(const char *file, int line, const char *function) {
+void __compilerrt_abort_impl(const char *file, int line, const char *function) {
__builtin_trap();
}
@@ -64,7 +64,7 @@ void compilerrt_abort_impl(const char *file, int line, const char *function) {
__attribute__((weak))
__attribute__((visibility("hidden")))
#endif
-void compilerrt_abort_impl(const char *file, int line, const char *function) {
+void __compilerrt_abort_impl(const char *file, int line, const char *function) {
abort();
}
diff --git a/lib/builtins/int_util.h b/lib/builtins/int_util.h
index a7b20ed66244..c3c87381ad8a 100644
--- a/lib/builtins/int_util.h
+++ b/lib/builtins/int_util.h
@@ -20,10 +20,10 @@
#define INT_UTIL_H
/** \brief Trigger a program abort (or panic for kernel code). */
-#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, __func__)
+#define compilerrt_abort() __compilerrt_abort_impl(__FILE__, __LINE__, __func__)
-NORETURN void compilerrt_abort_impl(const char *file, int line,
- const char *function);
+NORETURN void __compilerrt_abort_impl(const char *file, int line,
+ const char *function);
#define COMPILE_TIME_ASSERT(expr) COMPILE_TIME_ASSERT1(expr, __COUNTER__)
#define COMPILE_TIME_ASSERT1(expr, cnt) COMPILE_TIME_ASSERT2(expr, cnt)
diff --git a/lib/builtins/os_version_check.c b/lib/builtins/os_version_check.c
index 772e33333c0f..e0d40edc7e38 100644
--- a/lib/builtins/os_version_check.c
+++ b/lib/builtins/os_version_check.c
@@ -15,7 +15,6 @@
#ifdef __APPLE__
-#include <CoreFoundation/CoreFoundation.h>
#include <TargetConditionals.h>
#include <dispatch/dispatch.h>
#include <dlfcn.h>
@@ -28,6 +27,33 @@
static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
static dispatch_once_t DispatchOnceCounter;
+/* We can't include <CoreFoundation/CoreFoundation.h> directly from here, so
+ * just forward declare everything that we need from it. */
+
+typedef const void *CFDataRef, *CFAllocatorRef, *CFPropertyListRef,
+ *CFStringRef, *CFDictionaryRef, *CFTypeRef, *CFErrorRef;
+
+#if __LLP64__
+typedef unsigned long long CFTypeID;
+typedef unsigned long long CFOptionFlags;
+typedef signed long long CFIndex;
+#else
+typedef unsigned long CFTypeID;
+typedef unsigned long CFOptionFlags;
+typedef signed long CFIndex;
+#endif
+
+typedef unsigned char UInt8;
+typedef _Bool Boolean;
+typedef CFIndex CFPropertyListFormat;
+typedef uint32_t CFStringEncoding;
+
+/* kCFStringEncodingASCII analog. */
+#define CF_STRING_ENCODING_ASCII 0x0600
+/* kCFStringEncodingUTF8 analog. */
+#define CF_STRING_ENCODING_UTF8 0x08000100
+#define CF_PROPERTY_LIST_IMMUTABLE 0
+
typedef CFDataRef (*CFDataCreateWithBytesNoCopyFuncTy)(CFAllocatorRef,
const UInt8 *, CFIndex,
CFAllocatorRef);
@@ -55,8 +81,7 @@ static void parseSystemVersionPList(void *Unused) {
const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
if (!NullAllocator)
return;
- const CFAllocatorRef kCFAllocatorNull =
- *(const CFAllocatorRef *)NullAllocator;
+ const CFAllocatorRef AllocatorNull = *(const CFAllocatorRef *)NullAllocator;
CFDataCreateWithBytesNoCopyFuncTy CFDataCreateWithBytesNoCopyFunc =
(CFDataCreateWithBytesNoCopyFuncTy)dlsym(RTLD_DEFAULT,
"CFDataCreateWithBytesNoCopy");
@@ -140,21 +165,21 @@ static void parseSystemVersionPList(void *Unused) {
/* Get the file buffer into CF's format. We pass in a null allocator here *
* because we free PListBuf ourselves */
FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
- NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull);
+ NULL, PListBuf, (CFIndex)NumRead, AllocatorNull);
if (!FileContentsRef)
goto Fail;
if (CFPropertyListCreateWithDataFunc)
PListRef = (*CFPropertyListCreateWithDataFunc)(
- NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL);
+ NULL, FileContentsRef, CF_PROPERTY_LIST_IMMUTABLE, NULL, NULL);
else
PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
- NULL, FileContentsRef, kCFPropertyListImmutable, NULL);
+ NULL, FileContentsRef, CF_PROPERTY_LIST_IMMUTABLE, NULL);
if (!PListRef)
goto Fail;
CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
- NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull);
+ NULL, "ProductVersion", CF_STRING_ENCODING_ASCII, AllocatorNull);
if (!ProductVersion)
goto Fail;
CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
@@ -165,7 +190,7 @@ static void parseSystemVersionPList(void *Unused) {
char VersionStr[32];
if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
- sizeof(VersionStr), kCFStringEncodingUTF8))
+ sizeof(VersionStr), CF_STRING_ENCODING_UTF8))
goto Fail;
sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
diff --git a/lib/builtins/ppc/divtc3.c b/lib/builtins/ppc/divtc3.c
index 8ec41c528ab9..ef532b841145 100644
--- a/lib/builtins/ppc/divtc3.c
+++ b/lib/builtins/ppc/divtc3.c
@@ -4,6 +4,11 @@
#include "DD.h"
#include "../int_math.h"
+// Use DOUBLE_PRECISION because the soft-fp method we use is logb (on the upper
+// half of the long doubles), even though this file defines complex division for
+// 128-bit floats.
+#define DOUBLE_PRECISION
+#include "../fp_lib.h"
#if !defined(CRT_INFINITY) && defined(HUGE_VAL)
#define CRT_INFINITY HUGE_VAL
@@ -21,9 +26,10 @@ __divtc3(long double a, long double b, long double c, long double d)
DD dDD = { .ld = d };
int ilogbw = 0;
- const double logbw = crt_logb(crt_fmax(crt_fabs(cDD.s.hi), crt_fabs(dDD.s.hi) ));
-
- if (crt_isfinite(logbw))
+ const double logbw = __compiler_rt_logb(
+ crt_fmax(crt_fabs(cDD.s.hi), crt_fabs(dDD.s.hi)));
+
+ if (crt_isfinite(logbw))
{
ilogbw = (int)logbw;
diff --git a/lib/builtins/ppc/fixunstfti.c b/lib/builtins/ppc/fixunstfti.c
new file mode 100644
index 000000000000..fa21084cb576
--- /dev/null
+++ b/lib/builtins/ppc/fixunstfti.c
@@ -0,0 +1,106 @@
+//===-- lib/builtins/ppc/fixunstfti.c - Convert long double->int128 *-C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements converting the 128bit IBM/PowerPC long double (double-
+// double) data type to an unsigned 128 bit integer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../int_math.h"
+#define BIAS 1023
+
+/* Convert long double into an unsigned 128-bit integer. */
+__uint128_t __fixunstfti(long double input) {
+
+ /* If we are trying to convert a NaN, return the NaN bit pattern. */
+ if (crt_isnan(input)) {
+ return ((__uint128_t)0x7FF8000000000000ll) << 64 |
+ (__uint128_t)0x0000000000000000ll;
+ }
+
+ __uint128_t result, hiResult, loResult;
+ int hiExponent, loExponent, shift;
+ /* The long double representation, with the high and low portions of
+ * the long double, and the corresponding bit patterns of each double. */
+ union {
+ long double ld;
+ double d[2]; /* [0] is the high double, [1] is the low double. */
+ unsigned long long ull[2]; /* High and low doubles as 64-bit integers. */
+ } ldUnion;
+
+ /* If the long double is less than 1.0 or negative,
+ * return 0.0. */
+ if (input < 1.0)
+ return 0.0;
+
+ /* Retrieve the 64-bit patterns of high and low doubles.
+ * Compute the unbiased exponent of both high and low doubles by
+ * removing the signs, isolating the exponent, and subtracting
+ * the bias from it. */
+ ldUnion.ld = input;
+ hiExponent = ((ldUnion.ull[0] & 0x7FFFFFFFFFFFFFFFll) >> 52) - BIAS;
+ loExponent = ((ldUnion.ull[1] & 0x7FFFFFFFFFFFFFFFll) >> 52) - BIAS;
+
+ /* Convert each double into int64; they will be added to the int128 result.
+ * CASE 1: High or low double fits in int64
+ * - Convert the each double normally into int64.
+ *
+ * CASE 2: High or low double does not fit in int64
+ * - Scale the double to fit within a 64-bit integer
+ * - Calculate the shift (amount to scale the double by in the int128)
+ * - Clear all the bits of the exponent (with 0x800FFFFFFFFFFFFF)
+ * - Add BIAS+53 (0x4350000000000000) to exponent to correct the value
+ * - Scale (move) the double to the correct place in the int128
+ * (Move it by 2^53 places)
+ *
+ * Note: If the high double is assumed to be positive, an unsigned conversion
+ * from long double to 64-bit integer is needed. The low double can be either
+ * positive or negative, so a signed conversion is needed to retain the result
+ * of the low double and to ensure it does not simply get converted to 0. */
+
+ /* CASE 1 - High double fits in int64. */
+ if (hiExponent < 63) {
+ hiResult = (unsigned long long)ldUnion.d[0];
+ } else if (hiExponent < 128) {
+ /* CASE 2 - High double does not fit in int64, scale and convert it. */
+ shift = hiExponent - 54;
+ ldUnion.ull[0] &= 0x800FFFFFFFFFFFFFll;
+ ldUnion.ull[0] |= 0x4350000000000000ll;
+ hiResult = (unsigned long long)ldUnion.d[0];
+ hiResult <<= shift;
+ } else {
+ /* Detect cases for overflow. When the exponent of the high
+ * double is greater than 128 bits and when the long double
+ * input is positive, return the max 128-bit integer.
+ * For negative inputs with exponents > 128, return 1, like gcc. */
+ if (ldUnion.d[0] > 0) {
+ return ((__uint128_t)0xFFFFFFFFFFFFFFFFll) << 64 |
+ (__uint128_t)0xFFFFFFFFFFFFFFFFll;
+ } else {
+ return ((__uint128_t)0x0000000000000000ll) << 64 |
+ (__uint128_t)0x0000000000000001ll;
+ }
+ }
+
+ /* CASE 1 - Low double fits in int64. */
+ if (loExponent < 63) {
+ loResult = (long long)ldUnion.d[1];
+ } else {
+ /* CASE 2 - Low double does not fit in int64, scale and convert it. */
+ shift = loExponent - 54;
+ ldUnion.ull[1] &= 0x800FFFFFFFFFFFFFll;
+ ldUnion.ull[1] |= 0x4350000000000000ll;
+ loResult = (long long)ldUnion.d[1];
+ loResult <<= shift;
+ }
+
+ /* Add the high and low doublewords together to form a 128 bit integer. */
+ result = loResult + hiResult;
+ return result;
+}
diff --git a/lib/builtins/ppc/floattitf.c b/lib/builtins/ppc/floattitf.c
new file mode 100644
index 000000000000..b8e297b6b8d9
--- /dev/null
+++ b/lib/builtins/ppc/floattitf.c
@@ -0,0 +1,48 @@
+//===-- lib/builtins/ppc/floattitf.c - Convert int128->long double -*-C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements converting a signed 128 bit integer to a 128bit IBM /
+// PowerPC long double (double-double) value.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+
+/* Conversions from signed and unsigned 64-bit int to long double. */
+long double __floatditf(int64_t);
+long double __floatunditf(uint64_t);
+
+/* Convert a signed 128-bit integer to long double.
+ * This uses the following property: Let hi and lo be 64-bits each,
+ * and let signed_val_k() and unsigned_val_k() be the value of the
+ * argument interpreted as a signed or unsigned k-bit integer. Then,
+ *
+ * signed_val_128(hi,lo) = signed_val_64(hi) * 2^64 + unsigned_val_64(lo)
+ * = (long double)hi * 2^64 + (long double)lo,
+ *
+ * where (long double)hi and (long double)lo are signed and
+ * unsigned 64-bit integer to long double conversions, respectively.
+ */
+long double __floattitf(__int128_t arg) {
+ /* Split the int128 argument into 64-bit high and low int64 parts. */
+ int64_t ArgHiPart = (int64_t)(arg >> 64);
+ uint64_t ArgLoPart = (uint64_t)arg;
+
+ /* Convert each 64-bit part into long double. The high part
+ * must be a signed conversion and the low part an unsigned conversion
+ * to ensure the correct result. */
+ long double ConvertedHiPart = __floatditf(ArgHiPart);
+ long double ConvertedLoPart = __floatunditf(ArgLoPart);
+
+ /* The low bit of ArgHiPart corresponds to the 2^64 bit in arg.
+ * Multiply the high part by 2^64 to undo the right shift by 64-bits
+ * done in the splitting. Then, add to the low part to obtain the
+ * final result. */
+ return ((ConvertedHiPart * 0x1.0p64) + ConvertedLoPart);
+}
diff --git a/lib/cfi/CMakeLists.txt b/lib/cfi/CMakeLists.txt
index 7ed72bca5d23..463a1fd59915 100644
--- a/lib/cfi/CMakeLists.txt
+++ b/lib/cfi/CMakeLists.txt
@@ -1,6 +1,6 @@
add_compiler_rt_component(cfi)
-if(OS_NAME MATCHES "Linux")
+if(OS_NAME MATCHES "Linux" OR OS_NAME MATCHES "FreeBSD" OR OS_NAME MATCHES "NetBSD")
set(CFI_SOURCES cfi.cc)
include_directories(..)
diff --git a/lib/cfi/cfi.cc b/lib/cfi/cfi.cc
index a2f127f93cda..b0a943759678 100644
--- a/lib/cfi/cfi.cc
+++ b/lib/cfi/cfi.cc
@@ -13,15 +13,33 @@
#include <assert.h>
#include <elf.h>
+
+#include "sanitizer_common/sanitizer_common.h"
+#if SANITIZER_FREEBSD
+#include <sys/link_elf.h>
+#endif
#include <link.h>
#include <string.h>
+#include <stdlib.h>
#include <sys/mman.h>
+#if SANITIZER_LINUX
typedef ElfW(Phdr) Elf_Phdr;
typedef ElfW(Ehdr) Elf_Ehdr;
+typedef ElfW(Addr) Elf_Addr;
+typedef ElfW(Sym) Elf_Sym;
+typedef ElfW(Dyn) Elf_Dyn;
+#elif SANITIZER_FREEBSD
+#if SANITIZER_WORDSIZE == 64
+#define ElfW64_Dyn Elf_Dyn
+#define ElfW64_Sym Elf_Sym
+#else
+#define ElfW32_Dyn Elf_Dyn
+#define ElfW32_Sym Elf_Sym
+#endif
+#endif
#include "interception/interception.h"
-#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
#include "ubsan/ubsan_init.h"
#include "ubsan/ubsan_flags.h"
@@ -154,15 +172,25 @@ void ShadowBuilder::Add(uptr begin, uptr end, uptr cfi_check) {
*s = sv;
}
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD
void ShadowBuilder::Install() {
MprotectReadOnly(shadow_, GetShadowSize());
uptr main_shadow = GetShadow();
if (main_shadow) {
// Update.
+#if SANITIZER_LINUX
void *res = mremap((void *)shadow_, GetShadowSize(), GetShadowSize(),
MREMAP_MAYMOVE | MREMAP_FIXED, (void *)main_shadow);
CHECK(res != MAP_FAILED);
+#elif SANITIZER_NETBSD
+ void *res = mremap((void *)shadow_, GetShadowSize(), (void *)main_shadow,
+ GetShadowSize(), MAP_FIXED);
+ CHECK(res != MAP_FAILED);
+#else
+ void *res = MmapFixedOrDie(shadow_, GetShadowSize());
+ CHECK(res != MAP_FAILED);
+ ::memcpy(&shadow_, &main_shadow, GetShadowSize());
+#endif
} else {
// Initial setup.
CHECK_EQ(kCfiShadowLimitsStorageSize, GetPageSizeCached());
@@ -183,17 +211,17 @@ void ShadowBuilder::Install() {
// dlopen(RTLD_NOLOAD | RTLD_LAZY)
// dlsym("__cfi_check").
uptr find_cfi_check_in_dso(dl_phdr_info *info) {
- const ElfW(Dyn) *dynamic = nullptr;
+ const Elf_Dyn *dynamic = nullptr;
for (int i = 0; i < info->dlpi_phnum; ++i) {
if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
dynamic =
- (const ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
+ (const Elf_Dyn *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
break;
}
}
if (!dynamic) return 0;
uptr strtab = 0, symtab = 0, strsz = 0;
- for (const ElfW(Dyn) *p = dynamic; p->d_tag != PT_NULL; ++p) {
+ for (const Elf_Dyn *p = dynamic; p->d_tag != PT_NULL; ++p) {
if (p->d_tag == DT_SYMTAB)
symtab = p->d_un.d_ptr;
else if (p->d_tag == DT_STRTAB)
@@ -227,7 +255,7 @@ uptr find_cfi_check_in_dso(dl_phdr_info *info) {
return 0;
}
- for (const ElfW(Sym) *p = (const ElfW(Sym) *)symtab; (ElfW(Addr))p < strtab;
+ for (const Elf_Sym *p = (const Elf_Sym *)symtab; (Elf_Addr)p < strtab;
++p) {
// There is no reliable way to find the end of the symbol table. In
// lld-produces files, there are other sections between symtab and strtab.
diff --git a/lib/cfi/cfi_blacklist.txt b/lib/cfi/cfi_blacklist.txt
index 3d73508f5707..4a0f03949ca8 100644
--- a/lib/cfi/cfi_blacklist.txt
+++ b/lib/cfi/cfi_blacklist.txt
@@ -1,13 +1,11 @@
[cfi-unrelated-cast]
# The specification of std::get_temporary_buffer mandates a cast to
-# uninitialized T* (libstdc++, libc++, MSVC stdlib).
+# uninitialized T* (libstdc++, MSVC stdlib).
fun:_ZSt20get_temporary_buffer*
-fun:_ZNSt3__120get_temporary_buffer*
fun:*get_temporary_buffer@.*@std@@*
-# STL address-of magic (libstdc++, libc++).
+# STL address-of magic (libstdc++).
fun:*__addressof*
-fun:_ZNSt3__19addressof*
# Windows C++ stdlib headers that contain bad unrelated casts.
src:*xmemory0
diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc
index d4dbebc43a78..585bdceac764 100644
--- a/lib/dfsan/dfsan.cc
+++ b/lib/dfsan/dfsan.cc
@@ -423,7 +423,7 @@ static void dfsan_fini() {
static void dfsan_init(int argc, char **argv, char **envp) {
InitializeFlags();
- InitializePlatformEarly();
+ ::InitializePlatformEarly();
if (!MmapFixedNoReserve(ShadowAddr(), UnusedAddr() - ShadowAddr()))
Die();
diff --git a/lib/esan/CMakeLists.txt b/lib/esan/CMakeLists.txt
index 4de5c0205c1d..c880971e3dd9 100644
--- a/lib/esan/CMakeLists.txt
+++ b/lib/esan/CMakeLists.txt
@@ -14,6 +14,7 @@ set(ESAN_SOURCES
esan_interceptors.cpp
esan_linux.cpp
esan_sideline_linux.cpp
+ esan_sideline_bsd.cpp
cache_frag.cpp
working_set.cpp
working_set_posix.cpp)
diff --git a/lib/esan/esan_interceptors.cpp b/lib/esan/esan_interceptors.cpp
index 0c596f1cf37e..833faa2cd5bc 100644
--- a/lib/esan/esan_interceptors.cpp
+++ b/lib/esan/esan_interceptors.cpp
@@ -327,7 +327,7 @@ INTERCEPTOR(int, rmdir, char *path) {
// Signal-related interceptors
//===----------------------------------------------------------------------===//
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
typedef void (*signal_handler_t)(int);
INTERCEPTOR(signal_handler_t, signal, int signum, signal_handler_t handler) {
void *ctx;
@@ -344,7 +344,7 @@ INTERCEPTOR(signal_handler_t, signal, int signum, signal_handler_t handler) {
#define ESAN_MAYBE_INTERCEPT_SIGNAL
#endif
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
struct sigaction *oldact)
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
@@ -363,7 +363,11 @@ int real_sigaction(int signum, const void *act, void *oldact) {
if (REAL(sigaction) == nullptr) {
// With an instrumented allocator, this is called during interceptor init
// and we need a raw syscall solution.
+#if SANITIZER_LINUX
return internal_sigaction_syscall(signum, act, oldact);
+#else
+ return internal_sigaction(signum, act, oldact);
+#endif
}
return REAL(sigaction)(signum, (const struct sigaction *)act,
(struct sigaction *)oldact);
@@ -376,7 +380,7 @@ int real_sigaction(int signum, const void *act, void *oldact) {
#define ESAN_MAYBE_INTERCEPT_SIGACTION
#endif
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset) {
void *ctx;
diff --git a/lib/esan/esan_shadow.h b/lib/esan/esan_shadow.h
index 72a919a190d8..b76a9ccbd9e4 100644
--- a/lib/esan/esan_shadow.h
+++ b/lib/esan/esan_shadow.h
@@ -30,7 +30,7 @@ struct ApplicationRegion {
bool ShadowMergedWithPrev;
};
-#if SANITIZER_LINUX && defined(__x86_64__)
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && defined(__x86_64__)
// Linux x86_64
//
// Application memory falls into these 5 regions (ignoring the corner case
diff --git a/lib/esan/esan_sideline.h b/lib/esan/esan_sideline.h
index 04aff22f4cf0..74551fbde850 100644
--- a/lib/esan/esan_sideline.h
+++ b/lib/esan/esan_sideline.h
@@ -17,6 +17,7 @@
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_platform_limits_freebsd.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
namespace __esan {
diff --git a/lib/esan/esan_sideline_bsd.cpp b/lib/esan/esan_sideline_bsd.cpp
new file mode 100644
index 000000000000..3134d3776730
--- /dev/null
+++ b/lib/esan/esan_sideline_bsd.cpp
@@ -0,0 +1,35 @@
+//===-- esan_sideline_bsd.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of EfficiencySanitizer, a family of performance tuners.
+//
+// Support for a separate or "sideline" tool thread on FreeBSD.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_FREEBSD
+
+#include "esan_sideline.h"
+
+namespace __esan {
+
+static SidelineThread *TheThread;
+
+bool SidelineThread::launchThread(SidelineFunc takeSample, void *Arg,
+ u32 FreqMilliSec) {
+ return true;
+}
+
+bool SidelineThread::joinThread() {
+ return true;
+}
+
+} // namespace __esan
+
+#endif // SANITIZER_FREEBSD
diff --git a/lib/fuzzer/CMakeLists.txt b/lib/fuzzer/CMakeLists.txt
index 679318e460b5..caea9734fe53 100644
--- a/lib/fuzzer/CMakeLists.txt
+++ b/lib/fuzzer/CMakeLists.txt
@@ -3,8 +3,8 @@ set(LIBFUZZER_SOURCES
FuzzerDataFlowTrace.cpp
FuzzerDriver.cpp
FuzzerExtFunctionsDlsym.cpp
- FuzzerExtFunctionsDlsymWin.cpp
FuzzerExtFunctionsWeak.cpp
+ FuzzerExtFunctionsWindows.cpp
FuzzerExtraCounters.cpp
FuzzerIO.cpp
FuzzerIOPosix.cpp
@@ -25,6 +25,8 @@ set(LIBFUZZER_SOURCES
FuzzerUtilWindows.cpp)
set(LIBFUZZER_HEADERS
+ FuzzerBuiltins.h
+ FuzzerBuiltinsMsvc.h
FuzzerCommand.h
FuzzerCorpus.h
FuzzerDataFlowTrace.h
@@ -124,12 +126,12 @@ if(OS_NAME MATCHES "Linux|Fuchsia" AND COMPILER_RT_LIBCXX_PATH)
set(LIBCXX_${arch}_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_fuzzer_${arch})
add_custom_libcxx(libcxx_fuzzer_${arch} ${LIBCXX_${arch}_PREFIX}
CFLAGS ${TARGET_CFLAGS}
- -D_LIBCPP_ABI_VERSION=Fuzzer
-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=1
-fvisibility=hidden
CMAKE_ARGS -DCMAKE_CXX_COMPILER_WORKS=ON
-DLIBCXX_ENABLE_EXCEPTIONS=OFF
-DLIBCXX_ENABLE_SHARED=OFF
+ -DLIBCXX_ABI_NAMESPACE=Fuzzer
-DLIBCXX_CXX_ABI=none)
target_compile_options(RTfuzzer.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-build)
diff --git a/lib/fuzzer/FuzzerBuiltins.h b/lib/fuzzer/FuzzerBuiltins.h
new file mode 100644
index 000000000000..a80938d9a54d
--- /dev/null
+++ b/lib/fuzzer/FuzzerBuiltins.h
@@ -0,0 +1,36 @@
+//===- FuzzerBuiltins.h - Internal header for builtins ----------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Wrapper functions and marcos around builtin functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_BUILTINS_H
+#define LLVM_FUZZER_BUILTINS_H
+
+#include "FuzzerDefs.h"
+
+#if !LIBFUZZER_MSVC
+#include <cstdint>
+
+#define GET_CALLER_PC() __builtin_return_address(0)
+
+namespace fuzzer {
+
+inline uint8_t Bswap(uint8_t x) { return x; }
+inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
+inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
+inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
+
+inline uint32_t Clzll(unsigned long long X) { return __builtin_clzll(X); }
+inline uint32_t Clz(unsigned long long X) { return __builtin_clz(X); }
+inline int Popcountll(unsigned long long X) { return __builtin_popcountll(X); }
+
+} // namespace fuzzer
+
+#endif // !LIBFUZZER_MSVC
+#endif // LLVM_FUZZER_BUILTINS_H
diff --git a/lib/fuzzer/FuzzerBuiltinsMsvc.h b/lib/fuzzer/FuzzerBuiltinsMsvc.h
new file mode 100644
index 000000000000..67dd57ff9a93
--- /dev/null
+++ b/lib/fuzzer/FuzzerBuiltinsMsvc.h
@@ -0,0 +1,59 @@
+//===- FuzzerBuiltinsMSVC.h - Internal header for builtins ------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Wrapper functions and marcos that use intrinsics instead of builtin functions
+// which cannot be compiled by MSVC.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_BUILTINS_MSVC_H
+#define LLVM_FUZZER_BUILTINS_MSVC_H
+
+#include "FuzzerDefs.h"
+
+#if LIBFUZZER_MSVC
+#if !defined(_M_ARM) && !defined(_M_X64)
+#error "_BitScanReverse64 unavailable on this platform so MSVC is unsupported."
+#endif
+#include <intrin.h>
+#include <cstdint>
+#include <cstdlib>
+
+// __builtin_return_address() cannot be compiled with MSVC. Use the equivalent
+// from <intrin.h>
+#define GET_CALLER_PC() reinterpret_cast<uintptr_t>(_ReturnAddress())
+
+namespace fuzzer {
+
+inline uint8_t Bswap(uint8_t x) { return x; }
+// Use alternatives to __builtin functions from <stdlib.h> and <intrin.h> on
+// Windows since the builtins are not supported by MSVC.
+inline uint16_t Bswap(uint16_t x) { return _byteswap_ushort(x); }
+inline uint32_t Bswap(uint32_t x) { return _byteswap_ulong(x); }
+inline uint64_t Bswap(uint64_t x) { return _byteswap_uint64(x); }
+
+// The functions below were mostly copied from
+// compiler-rt/lib/builtins/int_lib.h which defines the __builtin functions used
+// outside of Windows.
+inline uint32_t Clzll(uint64_t X) {
+ unsigned long LeadZeroIdx = 0;
+ if (_BitScanReverse64(&LeadZeroIdx, X)) return 63 - LeadZeroIdx;
+ return 64;
+}
+
+inline uint32_t Clz(uint32_t X) {
+ unsigned long LeadZeroIdx = 0;
+ if (_BitScanReverse(&LeadZeroIdx, X)) return 31 - LeadZeroIdx;
+ return 32;
+}
+
+inline int Popcountll(unsigned long long X) { return __popcnt64(X); }
+
+} // namespace fuzzer
+
+#endif // LIBFUZER_MSVC
+#endif // LLVM_FUZZER_BUILTINS_MSVC_H
diff --git a/lib/fuzzer/FuzzerCommand.h b/lib/fuzzer/FuzzerCommand.h
index 255f571ecf31..9d258a228f89 100644
--- a/lib/fuzzer/FuzzerCommand.h
+++ b/lib/fuzzer/FuzzerCommand.h
@@ -81,7 +81,7 @@ public:
}
// Like hasArgument, but checks for "-[Flag]=...".
- bool hasFlag(const std::string &Flag) {
+ bool hasFlag(const std::string &Flag) const {
std::string Arg("-" + Flag + "=");
auto IsMatch = [&](const std::string &Other) {
return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
@@ -92,7 +92,7 @@ public:
// Returns the value of the first instance of a given flag, or an empty string
// if the flag isn't present. Ignores any occurrences after
// "-ignore_remaining_args=1", if present.
- std::string getFlagValue(const std::string &Flag) {
+ std::string getFlagValue(const std::string &Flag) const {
std::string Arg("-" + Flag + "=");
auto IsMatch = [&](const std::string &Other) {
return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h
index 8ad14656cffc..f844c07c7572 100644
--- a/lib/fuzzer/FuzzerCorpus.h
+++ b/lib/fuzzer/FuzzerCorpus.h
@@ -238,12 +238,6 @@ class InputCorpus {
return false;
}
- bool IsFeatureNew(size_t Idx, uint32_t NewSize, bool Shrink) {
- assert(NewSize);
- uint32_t OldSize = GetFeature(Idx % kFeatureSetSize);
- return OldSize == 0 || (Shrink && OldSize > NewSize);
- }
-
size_t NumFeatures() const { return NumAddedFeatures; }
size_t NumFeatureUpdates() const { return NumUpdatedFeatures; }
diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h
index a35c7a181b74..c3dccbcd86f5 100644
--- a/lib/fuzzer/FuzzerDefs.h
+++ b/lib/fuzzer/FuzzerDefs.h
@@ -82,6 +82,13 @@
#error "Support for your platform has not been implemented"
#endif
+#if defined(_MSC_VER) && !defined(__clang__)
+// MSVC compiler is being used.
+#define LIBFUZZER_MSVC 1
+#else
+#define LIBFUZZER_MSVC 0
+#endif
+
#ifndef __has_attribute
# define __has_attribute(x) 0
#endif
@@ -129,8 +136,15 @@
#if LIBFUZZER_WINDOWS
#define ATTRIBUTE_INTERFACE __declspec(dllexport)
+// This is used for __sancov_lowest_stack which is needed for
+// -fsanitize-coverage=stack-depth. That feature is not yet available on
+// Windows, so make the symbol static to avoid linking errors.
+#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \
+ __attribute__((tls_model("initial-exec"))) thread_local static
#else
#define ATTRIBUTE_INTERFACE __attribute__((visibility("default")))
+#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \
+ ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) thread_local
#endif
namespace fuzzer {
@@ -176,11 +190,6 @@ typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
-inline uint8_t Bswap(uint8_t x) { return x; }
-inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
-inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
-inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
-
uint8_t *ExtraCountersBegin();
uint8_t *ExtraCountersEnd();
void ClearExtraCounters();
diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp
index 783474a39e16..ff2a639ac4a3 100644
--- a/lib/fuzzer/FuzzerDriver.cpp
+++ b/lib/fuzzer/FuzzerDriver.cpp
@@ -615,13 +615,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
Options.PrintNewCovPcs = Flags.print_pcs;
Options.PrintNewCovFuncs = Flags.print_funcs;
Options.PrintFinalStats = Flags.print_final_stats;
- Options.PrintMutationStats = Flags.print_mutation_stats;
Options.PrintCorpusStats = Flags.print_corpus_stats;
Options.PrintCoverage = Flags.print_coverage;
- Options.PrintUnstableStats = Flags.print_unstable_stats;
- if (Flags.handle_unstable == TracePC::MinUnstable ||
- Flags.handle_unstable == TracePC::ZeroUnstable)
- Options.HandleUnstable = Flags.handle_unstable;
Options.DumpCoverage = Flags.dump_coverage;
if (Flags.exit_on_src_pos)
Options.ExitOnSrcPos = Flags.exit_on_src_pos;
diff --git a/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp b/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp
deleted file mode 100644
index 321b3ec5d414..000000000000
--- a/lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- FuzzerExtFunctionsDlsymWin.cpp - Interface to external functions ---===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// Implementation using dynamic loading for Windows.
-//===----------------------------------------------------------------------===//
-#include "FuzzerDefs.h"
-#if LIBFUZZER_WINDOWS
-
-#include "FuzzerExtFunctions.h"
-#include "FuzzerIO.h"
-#include "Windows.h"
-
-// This must be included after Windows.h.
-#include "Psapi.h"
-
-namespace fuzzer {
-
-ExternalFunctions::ExternalFunctions() {
- HMODULE Modules[1024];
- DWORD BytesNeeded;
- HANDLE CurrentProcess = GetCurrentProcess();
-
- if (!EnumProcessModules(CurrentProcess, Modules, sizeof(Modules),
- &BytesNeeded)) {
- Printf("EnumProcessModules failed (error: %d).\n", GetLastError());
- exit(1);
- }
-
- if (sizeof(Modules) < BytesNeeded) {
- Printf("Error: the array is not big enough to hold all loaded modules.\n");
- exit(1);
- }
-
- for (size_t i = 0; i < (BytesNeeded / sizeof(HMODULE)); i++)
- {
- FARPROC Fn;
-#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
- if (this->NAME == nullptr) { \
- Fn = GetProcAddress(Modules[i], #NAME); \
- if (Fn == nullptr) \
- Fn = GetProcAddress(Modules[i], #NAME "__dll"); \
- this->NAME = (decltype(ExternalFunctions::NAME)) Fn; \
- }
-#include "FuzzerExtFunctions.def"
-#undef EXT_FUNC
- }
-
-#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
- if (this->NAME == nullptr && WARN) \
- Printf("WARNING: Failed to find function \"%s\".\n", #NAME);
-#include "FuzzerExtFunctions.def"
-#undef EXT_FUNC
-}
-
-} // namespace fuzzer
-
-#endif // LIBFUZZER_WINDOWS
diff --git a/lib/fuzzer/FuzzerExtFunctionsWeak.cpp b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp
index a4e56fc27b8d..6a6ef4932f41 100644
--- a/lib/fuzzer/FuzzerExtFunctionsWeak.cpp
+++ b/lib/fuzzer/FuzzerExtFunctionsWeak.cpp
@@ -22,7 +22,7 @@
extern "C" {
// Declare these symbols as weak to allow them to be optionally defined.
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
- __attribute__((weak)) RETURN_TYPE NAME FUNC_SIG
+ __attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG
#include "FuzzerExtFunctions.def"
diff --git a/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp b/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp
deleted file mode 100644
index e10f7b4dcac2..000000000000
--- a/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-//===- FuzzerExtFunctionsWeakAlias.cpp - Interface to external functions --===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// Implementation using weak aliases. Works for Windows.
-//===----------------------------------------------------------------------===//
-#include "FuzzerDefs.h"
-#if LIBFUZZER_WINDOWS
-
-#include "FuzzerExtFunctions.h"
-#include "FuzzerIO.h"
-
-using namespace fuzzer;
-
-extern "C" {
-// Declare these symbols as weak to allow them to be optionally defined.
-#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
- RETURN_TYPE NAME##Def FUNC_SIG { \
- Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \
- exit(1); \
- } \
- RETURN_TYPE NAME FUNC_SIG __attribute__((weak, alias(#NAME "Def")));
-
-#include "FuzzerExtFunctions.def"
-
-#undef EXT_FUNC
-}
-
-template <typename T>
-static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) {
- if (Fun == FunDef) {
- if (WarnIfMissing)
- Printf("WARNING: Failed to find function \"%s\".\n", FnName);
- return nullptr;
- }
- return Fun;
-}
-
-namespace fuzzer {
-
-ExternalFunctions::ExternalFunctions() {
-#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
- this->NAME = GetFnPtr<decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN);
-
-#include "FuzzerExtFunctions.def"
-
-#undef EXT_FUNC
-}
-
-} // namespace fuzzer
-
-#endif // LIBFUZZER_WINDOWS
diff --git a/lib/fuzzer/FuzzerExtFunctionsWindows.cpp b/lib/fuzzer/FuzzerExtFunctionsWindows.cpp
new file mode 100644
index 000000000000..b01871439ca0
--- /dev/null
+++ b/lib/fuzzer/FuzzerExtFunctionsWindows.cpp
@@ -0,0 +1,83 @@
+//=== FuzzerExtWindows.cpp - Interface to external functions --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implementation of FuzzerExtFunctions for Windows. Uses alternatename when
+// compiled with MSVC. Uses weak aliases when compiled with clang. Unfortunately
+// the method each compiler supports is not supported by the other.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#if LIBFUZZER_WINDOWS
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+
+using namespace fuzzer;
+
+// Intermediate macro to ensure the parameter is expanded before stringified.
+#define STRINGIFY_(A) #A
+#define STRINGIFY(A) STRINGIFY_(A)
+
+#if LIBFUZZER_MSVC
+// Copied from compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h
+#if defined(_M_IX86) || defined(__i386__)
+#define WIN_SYM_PREFIX "_"
+#else
+#define WIN_SYM_PREFIX
+#endif
+
+// Declare external functions as having alternativenames, so that we can
+// determine if they are not defined.
+#define EXTERNAL_FUNC(Name, Default) \
+ __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \
+ Name) "=" WIN_SYM_PREFIX STRINGIFY(Default)))
+#else
+// Declare external functions as weak to allow them to default to a specified
+// function if not defined explicitly. We must use weak symbols because clang's
+// support for alternatename is not 100%, see
+// https://bugs.llvm.org/show_bug.cgi?id=40218 for more details.
+#define EXTERNAL_FUNC(Name, Default) \
+ __attribute__((weak, alias(STRINGIFY(Default))))
+#endif // LIBFUZZER_MSVC
+
+extern "C" {
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ RETURN_TYPE NAME##Def FUNC_SIG { \
+ Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \
+ exit(1); \
+ } \
+ EXTERNAL_FUNC(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG;
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+template <typename T>
+static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) {
+ if (Fun == FunDef) {
+ if (WarnIfMissing)
+ Printf("WARNING: Failed to find function \"%s\".\n", FnName);
+ return nullptr;
+ }
+ return Fun;
+}
+
+namespace fuzzer {
+
+ExternalFunctions::ExternalFunctions() {
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ this->NAME = GetFnPtr<decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN);
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_WINDOWS
diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def
index ba04bc25fd45..91281c979c50 100644
--- a/lib/fuzzer/FuzzerFlags.def
+++ b/lib/fuzzer/FuzzerFlags.def
@@ -17,7 +17,7 @@ FUZZER_FLAG_INT(runs, -1,
FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. "
"If 0, libFuzzer tries to guess a good value based on the corpus "
"and reports it. ")
-FUZZER_FLAG_INT(len_control, 1000, "Try generating small inputs first, "
+FUZZER_FLAG_INT(len_control, 100, "Try generating small inputs first, "
"then try larger inputs over time. Specifies the rate at which the length "
"limit is increased (smaller == faster). If 0, immediately try inputs with "
"size up to max_len.")
@@ -110,15 +110,6 @@ FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text"
FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated."
" If 1, dump coverage information as a"
" .sancov file at exit.")
-FUZZER_FLAG_INT(handle_unstable, 0, "Experimental."
- " Executes every input 3 times in total if a unique feature"
- " is found during the first execution."
- " If 1, we only use the minimum hit count from the 3 runs"
- " to determine whether an input is interesting."
- " If 2, we disregard edges that are found unstable for"
- " feature collection.")
-FUZZER_FLAG_INT(print_unstable_stats, 0, "Experimental."
- " If 1, print unstable statistics at exit.")
FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.")
FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.")
@@ -162,4 +153,3 @@ FUZZER_DEPRECATED_FLAG(use_equivalence_server)
FUZZER_FLAG_INT(analyze_dict, 0, "Experimental")
FUZZER_DEPRECATED_FLAG(use_clang_coverage)
FUZZER_FLAG_STRING(data_flow_trace, "Experimental: use the data flow trace")
-FUZZER_FLAG_INT(print_mutation_stats, 0, "Experimental")
diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp
index f3ead0ec5357..c4c31e82471f 100644
--- a/lib/fuzzer/FuzzerIO.cpp
+++ b/lib/fuzzer/FuzzerIO.cpp
@@ -31,7 +31,7 @@ long GetEpoch(const std::string &Path) {
}
Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
- std::ifstream T(Path);
+ std::ifstream T(Path, std::ios::binary);
if (ExitOnError && !T) {
Printf("No such directory: %s; exiting\n", Path.c_str());
exit(1);
@@ -51,7 +51,7 @@ Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
}
std::string FileToString(const std::string &Path) {
- std::ifstream T(Path);
+ std::ifstream T(Path, std::ios::binary);
return std::string((std::istreambuf_iterator<char>(T)),
std::istreambuf_iterator<char>());
}
@@ -100,14 +100,6 @@ std::string DirPlusFile(const std::string &DirPath,
return DirPath + GetSeparator() + FileName;
}
-std::string Basename(const std::string &Path, char Separator) {
- size_t Pos = Path.rfind(Separator);
- if (Pos == std::string::npos)
- return Path;
- assert(Pos < Path.size());
- return Path.substr(Pos + 1);
-}
-
void DupAndCloseStderr() {
int OutputFd = DuplicateFile(2);
if (OutputFd > 0) {
diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h
index 6d7757435b7b..b4a68190e780 100644
--- a/lib/fuzzer/FuzzerIO.h
+++ b/lib/fuzzer/FuzzerIO.h
@@ -68,7 +68,7 @@ void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);
char GetSeparator();
// Similar to the basename utility: returns the file name w/o the dir prefix.
-std::string Basename(const std::string &Path, char Separator = GetSeparator());
+std::string Basename(const std::string &Path);
FILE* OpenFile(int Fd, const char *Mode);
diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp
index 17e884d3c4c3..401b4cbbf74f 100644
--- a/lib/fuzzer/FuzzerIOPosix.cpp
+++ b/lib/fuzzer/FuzzerIOPosix.cpp
@@ -46,6 +46,13 @@ size_t FileSize(const std::string &Path) {
return St.st_size;
}
+std::string Basename(const std::string &Path) {
+ size_t Pos = Path.rfind(GetSeparator());
+ if (Pos == std::string::npos) return Path;
+ assert(Pos < Path.size());
+ return Path.substr(Pos + 1);
+}
+
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
Vector<std::string> *V, bool TopDir) {
auto E = GetEpoch(Dir);
diff --git a/lib/fuzzer/FuzzerIOWindows.cpp b/lib/fuzzer/FuzzerIOWindows.cpp
index 74853646b213..75dcaf72a940 100644
--- a/lib/fuzzer/FuzzerIOWindows.cpp
+++ b/lib/fuzzer/FuzzerIOWindows.cpp
@@ -72,6 +72,26 @@ bool IsFile(const std::string &Path) {
return IsFile(Path, Att);
}
+std::string Basename(const std::string &Path) {
+ size_t Pos = Path.find_last_of("/\\");
+ if (Pos == std::string::npos) return Path;
+ assert(Pos < Path.size());
+ return Path.substr(Pos + 1);
+}
+
+size_t FileSize(const std::string &Path) {
+ WIN32_FILE_ATTRIBUTE_DATA attr;
+ if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) {
+ Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
+ Path.c_str(), GetLastError());
+ return 0;
+ }
+ ULARGE_INTEGER size;
+ size.HighPart = attr.nFileSizeHigh;
+ size.LowPart = attr.nFileSizeLow;
+ return size.QuadPart;
+}
+
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
Vector<std::string> *V, bool TopDir) {
auto E = GetEpoch(Dir);
@@ -91,7 +111,7 @@ void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
return;
- Printf("No such directory: %s; exiting\n", Dir.c_str());
+ Printf("No such file or directory: %s; exiting\n", Dir.c_str());
exit(1);
}
diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h
index bfc898248adb..a7fdc89cba5f 100644
--- a/lib/fuzzer/FuzzerInternal.h
+++ b/lib/fuzzer/FuzzerInternal.h
@@ -67,7 +67,6 @@ public:
static void StaticGracefulExitCallback();
void ExecuteCallback(const uint8_t *Data, size_t Size);
- void CheckForUnstableCounters(const uint8_t *Data, size_t Size);
bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false,
InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr);
diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp
index 4bc88365a0b9..a32a30723004 100644
--- a/lib/fuzzer/FuzzerLoop.cpp
+++ b/lib/fuzzer/FuzzerLoop.cpp
@@ -275,7 +275,8 @@ NO_SANITIZE_MEMORY
void Fuzzer::AlarmCallback() {
assert(Options.UnitTimeoutSec > 0);
// In Windows Alarm callback is executed by a different thread.
-#if !LIBFUZZER_WINDOWS
+ // NetBSD's current behavior needs this change too.
+#if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD
if (!InFuzzingThread())
return;
#endif
@@ -354,13 +355,10 @@ void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {
void Fuzzer::PrintFinalStats() {
if (Options.PrintCoverage)
TPC.PrintCoverage();
- if (Options.PrintUnstableStats)
- TPC.PrintUnstableStats();
if (Options.DumpCoverage)
TPC.DumpCoverage();
if (Options.PrintCorpusStats)
Corpus.PrintStats();
- if (Options.PrintMutationStats) MD.PrintMutationStats();
if (!Options.PrintFinalStats)
return;
size_t ExecPerSec = execPerSec();
@@ -449,34 +447,6 @@ void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {
}
}
-void Fuzzer::CheckForUnstableCounters(const uint8_t *Data, size_t Size) {
- auto CBSetupAndRun = [&]() {
- ScopedEnableMsanInterceptorChecks S;
- UnitStartTime = system_clock::now();
- TPC.ResetMaps();
- RunningUserCallback = true;
- CB(Data, Size);
- RunningUserCallback = false;
- UnitStopTime = system_clock::now();
- };
-
- // Copy original run counters into our unstable counters
- TPC.InitializeUnstableCounters();
-
- // First Rerun
- CBSetupAndRun();
- TPC.UpdateUnstableCounters(Options.HandleUnstable);
-
- // Second Rerun
- CBSetupAndRun();
- TPC.UpdateUnstableCounters(Options.HandleUnstable);
-
- // Move minimum hit counts back to ModuleInline8bitCounters
- if (Options.HandleUnstable == TracePC::MinUnstable ||
- Options.HandleUnstable == TracePC::ZeroUnstable)
- TPC.ApplyUnstableCounters();
-}
-
bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
InputInfo *II, bool *FoundUniqFeatures) {
if (!Size)
@@ -487,17 +457,6 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
UniqFeatureSetTmp.clear();
size_t FoundUniqFeaturesOfII = 0;
size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
- bool NewFeaturesUnstable = false;
-
- if (Options.HandleUnstable || Options.PrintUnstableStats) {
- TPC.CollectFeatures([&](size_t Feature) {
- if (Corpus.IsFeatureNew(Feature, Size, Options.Shrink))
- NewFeaturesUnstable = true;
- });
- if (NewFeaturesUnstable)
- CheckForUnstableCounters(Data, Size);
- }
-
TPC.CollectFeatures([&](size_t Feature) {
if (Corpus.AddFeature(Feature, Size, Options.Shrink))
UniqFeatureSetTmp.push_back(Feature);
@@ -506,12 +465,10 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
II->UniqFeatureSet.end(), Feature))
FoundUniqFeaturesOfII++;
});
-
if (FoundUniqFeatures)
*FoundUniqFeatures = FoundUniqFeaturesOfII;
PrintPulseAndReportSlowInput(Data, Size);
size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
-
if (NumNewFeatures) {
TPC.UpdateObservedPCs();
Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
diff --git a/lib/fuzzer/FuzzerMutate.cpp b/lib/fuzzer/FuzzerMutate.cpp
index ff076cca683f..142b2b0b0014 100644
--- a/lib/fuzzer/FuzzerMutate.cpp
+++ b/lib/fuzzer/FuzzerMutate.cpp
@@ -30,36 +30,34 @@ MutationDispatcher::MutationDispatcher(Random &Rand,
DefaultMutators.insert(
DefaultMutators.begin(),
{
- {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes", 0, 0},
- {&MutationDispatcher::Mutate_InsertByte, "InsertByte", 0, 0},
+ {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"},
+ {&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
{&MutationDispatcher::Mutate_InsertRepeatedBytes,
- "InsertRepeatedBytes", 0, 0},
- {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte", 0, 0},
- {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit", 0, 0},
- {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes", 0, 0},
- {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt", 0,
- 0},
- {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt", 0,
- 0},
- {&MutationDispatcher::Mutate_CopyPart, "CopyPart", 0, 0},
- {&MutationDispatcher::Mutate_CrossOver, "CrossOver", 0, 0},
+ "InsertRepeatedBytes"},
+ {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
+ {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
+ {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
+ {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
+ {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"},
+ {&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
+ {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
{&MutationDispatcher::Mutate_AddWordFromManualDictionary,
- "ManualDict", 0, 0},
+ "ManualDict"},
{&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
- "PersAutoDict", 0, 0},
+ "PersAutoDict"},
});
if(Options.UseCmp)
DefaultMutators.push_back(
- {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP", 0, 0});
+ {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
if (EF->LLVMFuzzerCustomMutator)
- Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom", 0, 0});
+ Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
else
Mutators = DefaultMutators;
if (EF->LLVMFuzzerCustomCrossOver)
Mutators.push_back(
- {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver", 0, 0});
+ {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
}
static char RandCh(Random &Rand) {
@@ -466,7 +464,6 @@ void MutationDispatcher::RecordSuccessfulMutationSequence() {
if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
PersistentAutoDictionary.push_back({DE->GetW(), 1});
}
- RecordUsefulMutations();
}
void MutationDispatcher::PrintRecommendedDictionary() {
@@ -487,7 +484,8 @@ void MutationDispatcher::PrintRecommendedDictionary() {
void MutationDispatcher::PrintMutationSequence() {
Printf("MS: %zd ", CurrentMutatorSequence.size());
- for (auto M : CurrentMutatorSequence) Printf("%s-", M->Name);
+ for (auto M : CurrentMutatorSequence)
+ Printf("%s-", M.Name);
if (!CurrentDictionaryEntrySequence.empty()) {
Printf(" DE: ");
for (auto DE : CurrentDictionaryEntrySequence) {
@@ -515,13 +513,12 @@ size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
// in which case they will return 0.
// Try several times before returning un-mutated data.
for (int Iter = 0; Iter < 100; Iter++) {
- auto M = &Mutators[Rand(Mutators.size())];
- size_t NewSize = (this->*(M->Fn))(Data, Size, MaxSize);
+ auto M = Mutators[Rand(Mutators.size())];
+ size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
if (NewSize && NewSize <= MaxSize) {
if (Options.OnlyASCII)
ToASCII(Data, NewSize);
CurrentMutatorSequence.push_back(M);
- M->TotalCount++;
return NewSize;
}
}
@@ -562,21 +559,4 @@ void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
{W, std::numeric_limits<size_t>::max()});
}
-void MutationDispatcher::RecordUsefulMutations() {
- for (auto M : CurrentMutatorSequence) M->UsefulCount++;
-}
-
-void MutationDispatcher::PrintMutationStats() {
- Printf("\nstat::mutation_usefulness: ");
- for (size_t i = 0; i < Mutators.size(); i++) {
- double UsefulPercentage =
- Mutators[i].TotalCount
- ? (100.0 * Mutators[i].UsefulCount) / Mutators[i].TotalCount
- : 0;
- Printf("%.3f", UsefulPercentage);
- if (i < Mutators.size() - 1) Printf(",");
- }
- Printf("\n");
-}
-
} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerMutate.h b/lib/fuzzer/FuzzerMutate.h
index 828ecc13d866..a51c7fb44d46 100644
--- a/lib/fuzzer/FuzzerMutate.h
+++ b/lib/fuzzer/FuzzerMutate.h
@@ -93,16 +93,10 @@ public:
Random &GetRand() { return Rand; }
- void PrintMutationStats();
-
- void RecordUsefulMutations();
-
private:
struct Mutator {
size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
const char *Name;
- uint64_t UsefulCount;
- uint64_t TotalCount;
};
size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
@@ -141,7 +135,6 @@ public:
Dictionary PersistentAutoDictionary;
Vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
- Vector<Mutator *> CurrentMutatorSequence;
static const size_t kCmpDictionaryEntriesDequeSize = 16;
DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
@@ -156,6 +149,7 @@ public:
Vector<Mutator> Mutators;
Vector<Mutator> DefaultMutators;
+ Vector<Mutator> CurrentMutatorSequence;
};
} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h
index ce39c0876cd7..ab90df82a63d 100644
--- a/lib/fuzzer/FuzzerOptions.h
+++ b/lib/fuzzer/FuzzerOptions.h
@@ -52,11 +52,8 @@ struct FuzzingOptions {
bool PrintNewCovPcs = false;
int PrintNewCovFuncs = 0;
bool PrintFinalStats = false;
- bool PrintMutationStats = false;
bool PrintCorpusStats = false;
bool PrintCoverage = false;
- bool PrintUnstableStats = false;
- int HandleUnstable = 0;
bool DumpCoverage = false;
bool DetectLeaks = true;
int PurgeAllocatorIntervalSec = 1;
diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp
index 29ffc8e34fc0..80b33105bb22 100644
--- a/lib/fuzzer/FuzzerTracePC.cpp
+++ b/lib/fuzzer/FuzzerTracePC.cpp
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "FuzzerTracePC.h"
+#include "FuzzerBuiltins.h"
+#include "FuzzerBuiltinsMsvc.h"
#include "FuzzerCorpus.h"
#include "FuzzerDefs.h"
#include "FuzzerDictionary.h"
@@ -32,8 +34,7 @@ ATTRIBUTE_INTERFACE
uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs];
// Used by -fsanitize-coverage=stack-depth to track stack depth
-ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec")))
-thread_local uintptr_t __sancov_lowest_stack;
+ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC uintptr_t __sancov_lowest_stack;
namespace fuzzer {
@@ -57,49 +58,6 @@ size_t TracePC::GetTotalPCCoverage() {
return Res;
}
-template<class CallBack>
-void TracePC::IterateInline8bitCounters(CallBack CB) const {
- if (NumInline8bitCounters && NumInline8bitCounters == NumPCsInPCTables) {
- size_t CounterIdx = 0;
- for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
- uint8_t *Beg = ModuleCounters[i].Start;
- size_t Size = ModuleCounters[i].Stop - Beg;
- assert(Size == (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
- for (size_t j = 0; j < Size; j++, CounterIdx++)
- CB(i, j, CounterIdx);
- }
- }
-}
-
-// Initializes unstable counters by copying Inline8bitCounters to unstable
-// counters.
-void TracePC::InitializeUnstableCounters() {
- IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
- UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j];
- });
-}
-
-// Compares the current counters with counters from previous runs
-// and records differences as unstable edges.
-void TracePC::UpdateUnstableCounters(int UnstableMode) {
- IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
- if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter) {
- UnstableCounters[UnstableIdx].IsUnstable = true;
- if (UnstableMode == ZeroUnstable)
- UnstableCounters[UnstableIdx].Counter = 0;
- else if (UnstableMode == MinUnstable)
- UnstableCounters[UnstableIdx].Counter = std::min(
- ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter);
- }
- });
-}
-
-// Moves the minimum hit counts to ModuleCounters.
-void TracePC::ApplyUnstableCounters() {
- IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
- ModuleCounters[i].Start[j] = UnstableCounters[UnstableIdx].Counter;
- });
-}
void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
if (Start == Stop) return;
@@ -185,11 +143,42 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
ValueProfileMap.AddValueModPrime(Idx);
}
+/// \return the address of the previous instruction.
+/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.h`
+inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
+#if defined(__arm__)
+ // T32 (Thumb) branch instructions might be 16 or 32 bit long,
+ // so we return (pc-2) in that case in order to be safe.
+ // For A32 mode we return (pc-4) because all instructions are 32 bit long.
+ return (PC - 3) & (~1);
+#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__aarch64__)
+ // PCs are always 4 byte aligned.
+ return PC - 4;
+#elif defined(__sparc__) || defined(__mips__)
+ return PC - 8;
+#else
+ return PC - 1;
+#endif
+}
+
+/// \return the address of the next instruction.
+/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.cc`
+inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) {
+#if defined(__mips__)
+ return PC + 8;
+#elif defined(__powerpc__) || defined(__sparc__) || defined(__arm__) || \
+ defined(__aarch64__)
+ return PC + 4;
+#else
+ return PC + 1;
+#endif
+}
+
void TracePC::UpdateObservedPCs() {
Vector<uintptr_t> CoveredFuncs;
auto ObservePC = [&](uintptr_t PC) {
if (ObservedPCs.insert(PC).second && DoPrintNewPCs) {
- PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", PC + 1);
+ PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", GetNextInstructionPc(PC));
Printf("\n");
}
};
@@ -203,10 +192,15 @@ void TracePC::UpdateObservedPCs() {
if (NumPCsInPCTables) {
if (NumInline8bitCounters == NumPCsInPCTables) {
- IterateInline8bitCounters([&](int i, int j, int CounterIdx) {
- if (ModuleCounters[i].Start[j])
- Observe(ModulePCTable[i].Start[j]);
- });
+ for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
+ uint8_t *Beg = ModuleCounters[i].Start;
+ size_t Size = ModuleCounters[i].Stop - Beg;
+ assert(Size ==
+ (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
+ for (size_t j = 0; j < Size; j++)
+ if (Beg[j])
+ Observe(ModulePCTable[i].Start[j]);
+ }
} else if (NumGuards == NumPCsInPCTables) {
size_t GuardIdx = 1;
for (size_t i = 0; i < NumModules; i++) {
@@ -224,22 +218,11 @@ void TracePC::UpdateObservedPCs() {
for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N;
i++) {
Printf("\tNEW_FUNC[%zd/%zd]: ", i + 1, CoveredFuncs.size());
- PrintPC("%p %F %L", "%p", CoveredFuncs[i] + 1);
+ PrintPC("%p %F %L", "%p", GetNextInstructionPc(CoveredFuncs[i]));
Printf("\n");
}
}
-inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
- // TODO: this implementation is x86 only.
- // see sanitizer_common GetPreviousInstructionPc for full implementation.
- return PC - 1;
-}
-
-inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) {
- // TODO: this implementation is x86 only.
- // see sanitizer_common GetPreviousInstructionPc for full implementation.
- return PC + 1;
-}
static std::string GetModuleName(uintptr_t PC) {
char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++?
@@ -349,15 +332,6 @@ void TracePC::DumpCoverage() {
}
}
-void TracePC::PrintUnstableStats() {
- size_t count = 0;
- for (size_t i = 0; i < NumInline8bitCounters; i++)
- if (UnstableCounters[i].IsUnstable)
- count++;
- Printf("stat::stability_rate: %.2f\n",
- 100 - static_cast<float>(count * 100) / NumInline8bitCounters);
-}
-
// Value profile.
// We keep track of various values that affect control flow.
// These values are inserted into a bit-set-based hash map.
@@ -401,20 +375,14 @@ ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE
ATTRIBUTE_NO_SANITIZE_ALL
void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
uint64_t ArgXor = Arg1 ^ Arg2;
- uint64_t ArgDistance = __builtin_popcountll(ArgXor) + 1; // [1,65]
- uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance;
if (sizeof(T) == 4)
TORC4.Insert(ArgXor, Arg1, Arg2);
else if (sizeof(T) == 8)
TORC8.Insert(ArgXor, Arg1, Arg2);
- // TODO: remove these flags and instead use all metrics at once.
- if (UseValueProfileMask & 1)
- ValueProfileMap.AddValue(Idx);
- if (UseValueProfileMask & 2)
- ValueProfileMap.AddValue(
- PC * 64 + (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1));
- if (UseValueProfileMask & 4) // alternative way to use the hamming distance
- ValueProfileMap.AddValue(PC * 64 + ArgDistance);
+ uint64_t HammingDistance = Popcountll(ArgXor); // [0,64]
+ uint64_t AbsoluteDistance = (Arg1 == Arg2 ? 0 : Clzll(Arg1 - Arg2) + 1);
+ ValueProfileMap.AddValue(PC * 128 + HammingDistance);
+ ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance);
}
static size_t InternalStrnlen(const char *S, size_t MaxLen) {
@@ -455,7 +423,7 @@ extern "C" {
ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
uint32_t Idx = *Guard;
__sancov_trace_pc_pcs[Idx] = PC;
__sancov_trace_pc_guard_8bit_counters[Idx]++;
@@ -466,7 +434,7 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
void __sanitizer_cov_trace_pc() {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
uintptr_t Idx = PC & (((uintptr_t)1 << fuzzer::TracePC::kTracePcBits) - 1);
__sancov_trace_pc_pcs[Idx] = PC;
__sancov_trace_pc_guard_8bit_counters[Idx]++;
@@ -491,7 +459,7 @@ void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCallerCallee(PC, Callee);
}
@@ -499,7 +467,7 @@ ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
ATTRIBUTE_TARGET_POPCNT
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
}
@@ -510,7 +478,7 @@ ATTRIBUTE_TARGET_POPCNT
// the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however,
// should be changed later to make full use of instrumentation.
void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
}
@@ -518,7 +486,7 @@ ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
ATTRIBUTE_TARGET_POPCNT
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
}
@@ -526,7 +494,7 @@ ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
ATTRIBUTE_TARGET_POPCNT
void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
}
@@ -534,7 +502,7 @@ ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
ATTRIBUTE_TARGET_POPCNT
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
}
@@ -542,7 +510,7 @@ ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
ATTRIBUTE_TARGET_POPCNT
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
}
@@ -550,7 +518,7 @@ ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
ATTRIBUTE_TARGET_POPCNT
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
}
@@ -558,7 +526,7 @@ ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
ATTRIBUTE_TARGET_POPCNT
void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
}
@@ -572,7 +540,7 @@ void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
// Skip the most common and the most boring case.
if (Vals[N - 1] < 256 && Val < 256)
return;
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
size_t i;
uint64_t Token = 0;
for (i = 0; i < N; i++) {
@@ -593,7 +561,7 @@ ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
ATTRIBUTE_TARGET_POPCNT
void __sanitizer_cov_trace_div4(uint32_t Val) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0);
}
@@ -601,7 +569,7 @@ ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
ATTRIBUTE_TARGET_POPCNT
void __sanitizer_cov_trace_div8(uint64_t Val) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0);
}
@@ -609,7 +577,7 @@ ATTRIBUTE_INTERFACE
ATTRIBUTE_NO_SANITIZE_ALL
ATTRIBUTE_TARGET_POPCNT
void __sanitizer_cov_trace_gep(uintptr_t Idx) {
- uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0);
}
diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h
index 097ba69bdc08..46d6c24887fd 100644
--- a/lib/fuzzer/FuzzerTracePC.h
+++ b/lib/fuzzer/FuzzerTracePC.h
@@ -74,11 +74,6 @@ class TracePC {
// How many bits of PC are used from __sanitizer_cov_trace_pc.
static const size_t kTracePcBits = 18;
- enum HandleUnstableOptions {
- MinUnstable = 1,
- ZeroUnstable = 2,
- };
-
void HandleInit(uint32_t *Start, uint32_t *Stop);
void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop);
void HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop);
@@ -109,7 +104,6 @@ class TracePC {
void PrintCoverage();
void DumpCoverage();
- void PrintUnstableStats();
template<class CallBack>
void IterateCoveredFunctions(CallBack CB);
@@ -142,18 +136,7 @@ class TracePC {
void SetFocusFunction(const std::string &FuncName);
bool ObservedFocusFunction();
- void InitializeUnstableCounters();
- void UpdateUnstableCounters(int UnstableMode);
- void ApplyUnstableCounters();
-
private:
- struct UnstableEdge {
- uint8_t Counter;
- bool IsUnstable;
- };
-
- UnstableEdge UnstableCounters[kNumPCs];
-
bool UseCounters = false;
uint32_t UseValueProfileMask = false;
bool DoPrintNewPCs = false;
@@ -185,9 +168,6 @@ private:
Set<uintptr_t> ObservedPCs;
std::unordered_map<uintptr_t, uintptr_t> ObservedFuncs; // PC => Counter.
- template <class Callback>
- void IterateInline8bitCounters(Callback CB) const;
-
std::pair<size_t, size_t> FocusFunction = {-1, -1}; // Module and PC IDs.
ValueBitMap ValueProfileMap;
diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h
index 8c5c57c3ab83..d2f1d5de4267 100644
--- a/lib/fuzzer/FuzzerUtil.h
+++ b/lib/fuzzer/FuzzerUtil.h
@@ -12,8 +12,10 @@
#ifndef LLVM_FUZZER_UTIL_H
#define LLVM_FUZZER_UTIL_H
-#include "FuzzerDefs.h"
+#include "FuzzerBuiltins.h"
+#include "FuzzerBuiltinsMsvc.h"
#include "FuzzerCommand.h"
+#include "FuzzerDefs.h"
namespace fuzzer {
@@ -84,7 +86,7 @@ std::string SearchRegexCmd(const std::string &Regex);
size_t SimpleFastHash(const uint8_t *Data, size_t Size);
-inline uint32_t Log(uint32_t X) { return 32 - __builtin_clz(X) - 1; }
+inline uint32_t Log(uint32_t X) { return 32 - Clz(X) - 1; }
} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerUtilFuchsia.cpp b/lib/fuzzer/FuzzerUtilFuchsia.cpp
index cd2bb7438e9d..cd48fefef352 100644
--- a/lib/fuzzer/FuzzerUtilFuchsia.cpp
+++ b/lib/fuzzer/FuzzerUtilFuchsia.cpp
@@ -49,9 +49,6 @@ void CrashTrampolineAsm() __asm__("CrashTrampolineAsm");
namespace {
-// TODO(phosek): remove this and replace it with ZX_TIME_INFINITE
-#define ZX_TIME_INFINITE_OLD INT64_MAX
-
// A magic value for the Zircon exception port, chosen to spell 'FUZZING'
// when interpreted as a byte sequence on little-endian platforms.
const uint64_t kFuzzingCrash = 0x474e495a5a5546;
@@ -237,7 +234,7 @@ void CrashHandler(zx_handle_t *Event) {
"_zx_object_signal");
zx_port_packet_t Packet;
- ExitOnErr(_zx_port_wait(Port.Handle, ZX_TIME_INFINITE_OLD, &Packet),
+ ExitOnErr(_zx_port_wait(Port.Handle, ZX_TIME_INFINITE, &Packet),
"_zx_port_wait");
// At this point, we want to get the state of the crashing thread, but
@@ -315,8 +312,8 @@ void SetSignalHandler(const FuzzingOptions &Options) {
ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create");
std::thread T(CrashHandler, &Event);
- zx_status_t Status = _zx_object_wait_one(Event, ZX_USER_SIGNAL_0,
- ZX_TIME_INFINITE_OLD, nullptr);
+ zx_status_t Status =
+ _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, nullptr);
_zx_handle_close(Event);
ExitOnErr(Status, "_zx_object_wait_one");
@@ -378,19 +375,28 @@ int ExecuteCommand(const Command &Cmd) {
Argv[i] = Args[i].c_str();
Argv[Argc] = nullptr;
- // Determine stdout
+ // Determine output. On Fuchsia, the fuzzer is typically run as a component
+ // that lacks a mutable working directory. Fortunately, when this is the case
+ // a mutable output directory must be specified using "-artifact_prefix=...",
+ // so write the log file(s) there.
int FdOut = STDOUT_FILENO;
-
if (Cmd.hasOutputFile()) {
- auto Filename = Cmd.getOutputFile();
- FdOut = open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
+ std::string Path;
+ if (Cmd.hasFlag("artifact_prefix"))
+ Path = Cmd.getFlagValue("artifact_prefix") + "/" + Cmd.getOutputFile();
+ else
+ Path = Cmd.getOutputFile();
+ FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
if (FdOut == -1) {
- Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(),
+ Printf("libFuzzer: failed to open %s: %s\n", Path.c_str(),
strerror(errno));
return ZX_ERR_IO;
}
}
- auto CloseFdOut = at_scope_exit([&]() { close(FdOut); } );
+ auto CloseFdOut = at_scope_exit([FdOut]() {
+ if (FdOut != STDOUT_FILENO)
+ close(FdOut);
+ });
// Determine stderr
int FdErr = STDERR_FILENO;
@@ -440,7 +446,7 @@ int ExecuteCommand(const Command &Cmd) {
// Now join the process and return the exit status.
if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED,
- ZX_TIME_INFINITE_OLD, nullptr)) != ZX_OK) {
+ ZX_TIME_INFINITE, nullptr)) != ZX_OK) {
Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
_zx_status_get_string(rc));
return rc;
diff --git a/lib/fuzzer/FuzzerUtilWindows.cpp b/lib/fuzzer/FuzzerUtilWindows.cpp
index 8227e778ea0a..393b4768be7e 100644
--- a/lib/fuzzer/FuzzerUtilWindows.cpp
+++ b/lib/fuzzer/FuzzerUtilWindows.cpp
@@ -24,7 +24,7 @@
#include <windows.h>
// This must be included after windows.h.
-#include <Psapi.h>
+#include <psapi.h>
namespace fuzzer {
@@ -179,7 +179,9 @@ const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
}
std::string DisassembleCmd(const std::string &FileName) {
- if (ExecuteCommand("dumpbin /summary > nul") == 0)
+ Vector<std::string> command_vector;
+ command_vector.push_back("dumpbin /summary > nul");
+ if (ExecuteCommand(Command(command_vector)) == 0)
return "dumpbin /disasm " + FileName;
Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
exit(1);
diff --git a/lib/fuzzer/afl/afl_driver.cpp b/lib/fuzzer/afl/afl_driver.cpp
index fa494c03bde0..5a10c0d27f3a 100644
--- a/lib/fuzzer/afl/afl_driver.cpp
+++ b/lib/fuzzer/afl/afl_driver.cpp
@@ -289,7 +289,7 @@ extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
// Execute any files provided as parameters.
int ExecuteFilesOnyByOne(int argc, char **argv) {
for (int i = 1; i < argc; i++) {
- std::ifstream in(argv[i]);
+ std::ifstream in(argv[i], std::ios::binary);
in.seekg(0, in.end);
size_t length = in.tellg();
in.seekg (0, in.beg);
diff --git a/lib/fuzzer/tests/CMakeLists.txt b/lib/fuzzer/tests/CMakeLists.txt
index ed5807168301..6abb72def3e1 100644
--- a/lib/fuzzer/tests/CMakeLists.txt
+++ b/lib/fuzzer/tests/CMakeLists.txt
@@ -1,3 +1,5 @@
+include(CompilerRTCompile)
+
set(LIBFUZZER_UNITTEST_CFLAGS
${COMPILER_RT_UNITTEST_CFLAGS}
${COMPILER_RT_GTEST_CFLAGS}
@@ -17,12 +19,12 @@ list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS --driver-mode=g++)
if(APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lc++ -lpthread)
-else()
+elseif(NOT WIN32)
list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lstdc++ -lpthread)
endif()
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH)
- list(APPEND LIBFUZZER_UNITTEST_CFLAGS -nostdinc++ -D_LIBCPP_ABI_VERSION=Fuzzer)
+ list(APPEND LIBFUZZER_UNITTEST_CFLAGS -nostdinc++)
endif()
if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH)
@@ -45,7 +47,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH)
set(LIBFUZZER_TEST_RUNTIME_DEPS libcxx_fuzzer_${arch}-build)
- set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${COMPILER_RT_LIBCXX_PATH}/include)
+ set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
set(LIBFUZZER_TEST_RUNTIME_LINK_FLAGS ${LIBCXX_${arch}_PREFIX}/lib/libc++.a)
endif()
diff --git a/lib/fuzzer/tests/FuzzerUnittest.cpp b/lib/fuzzer/tests/FuzzerUnittest.cpp
index e3b06702603d..7cdd44582329 100644
--- a/lib/fuzzer/tests/FuzzerUnittest.cpp
+++ b/lib/fuzzer/tests/FuzzerUnittest.cpp
@@ -34,6 +34,13 @@ TEST(Fuzzer, Basename) {
EXPECT_EQ(Basename("/bar"), "bar");
EXPECT_EQ(Basename("foo/x"), "x");
EXPECT_EQ(Basename("foo/"), "");
+#if LIBFUZZER_WINDOWS
+ EXPECT_EQ(Basename("foo\\bar"), "bar");
+ EXPECT_EQ(Basename("foo\\bar/baz"), "baz");
+ EXPECT_EQ(Basename("\\bar"), "bar");
+ EXPECT_EQ(Basename("foo\\x"), "x");
+ EXPECT_EQ(Basename("foo\\"), "");
+#endif
}
TEST(Fuzzer, CrossOver) {
diff --git a/lib/hwasan/CMakeLists.txt b/lib/hwasan/CMakeLists.txt
index 42bf4366f192..20ab94dc0446 100644
--- a/lib/hwasan/CMakeLists.txt
+++ b/lib/hwasan/CMakeLists.txt
@@ -7,9 +7,11 @@ set(HWASAN_RTL_SOURCES
hwasan_dynamic_shadow.cc
hwasan_interceptors.cc
hwasan_linux.cc
+ hwasan_memintrinsics.cc
hwasan_poisoning.cc
hwasan_report.cc
hwasan_thread.cc
+ hwasan_thread_list.cc
)
set(HWASAN_RTL_CXX_SOURCES
@@ -25,8 +27,12 @@ set(HWASAN_RTL_HEADERS
hwasan_mapping.h
hwasan_poisoning.h
hwasan_report.h
- hwasan_thread.h)
+ hwasan_thread.h
+ hwasan_thread_list.h
+ )
+set(HWASAN_DEFINITIONS)
+append_list_if(COMPILER_RT_HWASAN_WITH_INTERCEPTORS HWASAN_WITH_INTERCEPTORS=1 HWASAN_DEFINITIONS)
set(HWASAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})
append_rtti_flag(OFF HWASAN_RTL_CFLAGS)
@@ -36,6 +42,14 @@ append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding HWASAN_RTL_CFLA
set(HWASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS})
+if(ANDROID)
+# Put most Sanitizer shared libraries in the global group. For more details, see
+# android-changes-for-ndk-developers.md#changes-to-library-search-order
+ if (COMPILER_RT_HAS_Z_GLOBAL)
+ list(APPEND HWASAN_DYNAMIC_LINK_FLAGS -Wl,-z,global)
+ endif()
+endif()
+
set(HWASAN_DYNAMIC_CFLAGS ${HWASAN_RTL_CFLAGS})
append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
-ftls-model=initial-exec HWASAN_DYNAMIC_CFLAGS)
@@ -47,7 +61,10 @@ append_list_if(COMPILER_RT_HAS_LIBDL dl HWASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBRT rt HWASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBM m HWASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread HWASAN_DYNAMIC_LIBS)
-append_list_if(COMPILER_RT_HAS_LIBLOG log HWASAN_DYNAMIC_LIBS)
+
+if (TARGET cxx-headers OR HAVE_LIBCXX)
+ set(HWASAN_DEPS cxx-headers)
+endif()
# Static runtime library.
add_compiler_rt_component(hwasan)
@@ -56,23 +73,31 @@ add_compiler_rt_object_libraries(RTHwasan
ARCHS ${HWASAN_SUPPORTED_ARCH}
SOURCES ${HWASAN_RTL_SOURCES}
ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}
- CFLAGS ${HWASAN_RTL_CFLAGS})
+ CFLAGS ${HWASAN_RTL_CFLAGS}
+ DEFS ${HWASAN_DEFINITIONS}
+ DEPS ${HWASAN_DEPS})
add_compiler_rt_object_libraries(RTHwasan_cxx
ARCHS ${HWASAN_SUPPORTED_ARCH}
SOURCES ${HWASAN_RTL_CXX_SOURCES}
ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}
- CFLAGS ${HWASAN_RTL_CFLAGS})
+ CFLAGS ${HWASAN_RTL_CFLAGS}
+ DEFS ${HWASAN_DEFINITIONS}
+ DEPS ${HWASAN_DEPS})
add_compiler_rt_object_libraries(RTHwasan_dynamic
ARCHS ${HWASAN_SUPPORTED_ARCH}
SOURCES ${HWASAN_RTL_SOURCES} ${HWASAN_RTL_CXX_SOURCES}
ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}
- CFLAGS ${HWASAN_DYNAMIC_CFLAGS})
+ CFLAGS ${HWASAN_DYNAMIC_CFLAGS}
+ DEFS ${HWASAN_DEFINITIONS}
+ DEPS ${HWASAN_DEPS})
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc "")
add_compiler_rt_object_libraries(RTHwasan_dynamic_version_script_dummy
ARCHS ${HWASAN_SUPPORTED_ARCH}
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
- CFLAGS ${HWASAN_DYNAMIC_CFLAGS})
+ CFLAGS ${HWASAN_DYNAMIC_CFLAGS}
+ DEFS ${HWASAN_DEFINITIONS}
+ DEPS ${HWASAN_DEPS})
foreach(arch ${HWASAN_SUPPORTED_ARCH})
add_compiler_rt_runtime(clang_rt.hwasan
@@ -121,6 +146,7 @@ foreach(arch ${HWASAN_SUPPORTED_ARCH})
RTSanitizerCommonCoverage
RTSanitizerCommonSymbolizer
RTUbsan
+ RTUbsan_cxx
# The only purpose of RTHWAsan_dynamic_version_script_dummy is to
# carry a dependency of the shared runtime on the version script.
# Replacing it with a straightforward
diff --git a/lib/hwasan/hwasan.cc b/lib/hwasan/hwasan.cc
index 7dab8249e3f7..e2bfea5e4226 100644
--- a/lib/hwasan/hwasan.cc
+++ b/lib/hwasan/hwasan.cc
@@ -13,19 +13,20 @@
//===----------------------------------------------------------------------===//
#include "hwasan.h"
-#include "hwasan_mapping.h"
+#include "hwasan_checks.h"
#include "hwasan_poisoning.h"
#include "hwasan_report.h"
#include "hwasan_thread.h"
+#include "hwasan_thread_list.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
-#include "sanitizer_common/sanitizer_stackdepot.h"
#include "ubsan/ubsan_flags.h"
#include "ubsan/ubsan_init.h"
@@ -36,17 +37,17 @@ using namespace __sanitizer;
namespace __hwasan {
void EnterSymbolizer() {
- HwasanThread *t = GetCurrentThread();
+ Thread *t = GetCurrentThread();
CHECK(t);
t->EnterSymbolizer();
}
void ExitSymbolizer() {
- HwasanThread *t = GetCurrentThread();
+ Thread *t = GetCurrentThread();
CHECK(t);
t->LeaveSymbolizer();
}
bool IsInSymbolizer() {
- HwasanThread *t = GetCurrentThread();
+ Thread *t = GetCurrentThread();
return t && t->InSymbolizer();
}
@@ -57,6 +58,7 @@ Flags *flags() {
}
int hwasan_inited = 0;
+int hwasan_shadow_inited = 0;
bool hwasan_init_is_running;
int hwasan_report_count = 0;
@@ -86,7 +88,18 @@ static void InitializeFlags() {
cf.check_printf = false;
cf.intercept_tls_get_addr = true;
cf.exitcode = 99;
+ // Sigtrap is used in error reporting.
cf.handle_sigtrap = kHandleSignalExclusive;
+
+#if SANITIZER_ANDROID
+ // Let platform handle other signals. It is better at reporting them then we
+ // are.
+ cf.handle_segv = kHandleSignalNo;
+ cf.handle_sigbus = kHandleSignalNo;
+ cf.handle_abort = kHandleSignalNo;
+ cf.handle_sigill = kHandleSignalNo;
+ cf.handle_sigfpe = kHandleSignalNo;
+#endif
OverrideCommonFlags(cf);
}
@@ -119,7 +132,8 @@ static void InitializeFlags() {
#if HWASAN_CONTAINS_UBSAN
ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
#endif
- VPrintf(1, "HWASAN_OPTIONS: %s\n", hwasan_options ? hwasan_options : "<empty>");
+ VPrintf(1, "HWASAN_OPTIONS: %s\n",
+ hwasan_options ? hwasan_options : "<empty>");
InitializeCommonFlags();
@@ -130,8 +144,13 @@ static void InitializeFlags() {
void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
void *context, bool request_fast_unwind) {
- HwasanThread *t = GetCurrentThread();
- if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) {
+ Thread *t = GetCurrentThread();
+ if (!t) {
+ // the thread is still being created.
+ stack->size = 0;
+ return;
+ }
+ if (!StackTrace::WillUseFastUnwind(request_fast_unwind)) {
// Block reports from our interceptors during _Unwind_Backtrace.
SymbolizerScope sym_scope;
return stack->Unwind(max_s, pc, bp, context, 0, 0, request_fast_unwind);
@@ -140,11 +159,6 @@ void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
request_fast_unwind);
}
-void PrintWarning(uptr pc, uptr bp) {
- GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
- ReportInvalidAccess(&stack, 0);
-}
-
static void HWAsanCheckFailed(const char *file, int line, const char *cond,
u64 v1, u64 v2) {
Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
@@ -153,6 +167,84 @@ static void HWAsanCheckFailed(const char *file, int line, const char *cond,
Die();
}
+static constexpr uptr kMemoryUsageBufferSize = 4096;
+
+static void HwasanFormatMemoryUsage(InternalScopedString &s) {
+ HwasanThreadList &thread_list = hwasanThreadList();
+ auto thread_stats = thread_list.GetThreadStats();
+ auto *sds = StackDepotGetStats();
+ AllocatorStatCounters asc;
+ GetAllocatorStats(asc);
+ s.append(
+ "HWASAN pid: %d rss: %zd threads: %zd stacks: %zd"
+ " thr_aux: %zd stack_depot: %zd uniq_stacks: %zd"
+ " heap: %zd",
+ internal_getpid(), GetRSS(), thread_stats.n_live_threads,
+ thread_stats.total_stack_size,
+ thread_stats.n_live_threads * thread_list.MemoryUsedPerThread(),
+ sds->allocated, sds->n_uniq_ids, asc[AllocatorStatMapped]);
+}
+
+#if SANITIZER_ANDROID
+static char *memory_usage_buffer = nullptr;
+
+#define PR_SET_VMA 0x53564d41
+#define PR_SET_VMA_ANON_NAME 0
+
+static void InitMemoryUsage() {
+ memory_usage_buffer =
+ (char *)MmapOrDie(kMemoryUsageBufferSize, "memory usage string");
+ CHECK(memory_usage_buffer);
+ memory_usage_buffer[0] = '\0';
+ CHECK(internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME,
+ (uptr)memory_usage_buffer, kMemoryUsageBufferSize,
+ (uptr)memory_usage_buffer) == 0);
+}
+
+void UpdateMemoryUsage() {
+ if (!flags()->export_memory_stats)
+ return;
+ if (!memory_usage_buffer)
+ InitMemoryUsage();
+ InternalScopedString s(kMemoryUsageBufferSize);
+ HwasanFormatMemoryUsage(s);
+ internal_strncpy(memory_usage_buffer, s.data(), kMemoryUsageBufferSize - 1);
+ memory_usage_buffer[kMemoryUsageBufferSize - 1] = '\0';
+}
+#else
+void UpdateMemoryUsage() {}
+#endif
+
+struct FrameDescription {
+ uptr PC;
+ const char *Descr;
+};
+
+struct FrameDescriptionArray {
+ FrameDescription *beg, *end;
+};
+
+static InternalMmapVectorNoCtor<FrameDescriptionArray> AllFrames;
+
+void InitFrameDescriptors(uptr b, uptr e) {
+ FrameDescription *beg = reinterpret_cast<FrameDescription *>(b);
+ FrameDescription *end = reinterpret_cast<FrameDescription *>(e);
+ if (beg == end)
+ return;
+ AllFrames.push_back({beg, end});
+ if (Verbosity())
+ for (FrameDescription *frame_descr = beg; frame_descr < end; frame_descr++)
+ Printf("Frame: %p %s\n", frame_descr->PC, frame_descr->Descr);
+}
+
+const char *GetStackFrameDescr(uptr pc) {
+ for (uptr i = 0, n = AllFrames.size(); i < n; i++)
+ for (auto p = AllFrames[i].beg; p < AllFrames[i].end; p++)
+ if (p->PC == pc)
+ return p->Descr;
+ return nullptr;
+}
+
} // namespace __hwasan
// Interface.
@@ -161,6 +253,20 @@ using namespace __hwasan;
uptr __hwasan_shadow_memory_dynamic_address; // Global interface symbol.
+void __hwasan_shadow_init() {
+ if (hwasan_shadow_inited) return;
+ if (!InitShadow()) {
+ Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n");
+ DumpProcessMap();
+ Die();
+ }
+ hwasan_shadow_inited = 1;
+}
+
+void __hwasan_init_frames(uptr beg, uptr end) {
+ InitFrameDescriptors(beg, end);
+}
+
void __hwasan_init() {
CHECK(!hwasan_init_is_running);
if (hwasan_inited) return;
@@ -177,18 +283,20 @@ void __hwasan_init() {
__sanitizer_set_report_path(common_flags()->log_path);
+ AndroidTestTlsSlot();
+
DisableCoreDumperIfNecessary();
- if (!InitShadow()) {
- Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n");
- if (HWASAN_FIXED_MAPPING) {
- Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
- Printf("FATAL: Disabling ASLR is known to cause this error.\n");
- Printf("FATAL: If running under GDB, try "
- "'set disable-randomization off'.\n");
- }
- DumpProcessMap();
- Die();
- }
+
+ __hwasan_shadow_init();
+
+ InitThreads();
+ hwasanThreadList().CreateCurrentThread();
+
+ MadviseShadow();
+
+ SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
+ // This may call libc -> needs initialized shadow.
+ AndroidLogInit();
InitializeInterceptors();
InstallDeadlySignalHandlers(HwasanOnDeadlySignal);
@@ -198,14 +306,11 @@ void __hwasan_init() {
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
- HwasanTSDInit(HwasanTSDDtor);
+ HwasanTSDInit();
+ HwasanTSDThreadInit();
HwasanAllocatorInit();
- HwasanThread *main_thread = HwasanThread::Create(nullptr, nullptr);
- SetCurrentThread(main_thread);
- main_thread->ThreadStart();
-
#if HWASAN_CONTAINS_UBSAN
__ubsan::InitAsPlugin();
#endif
@@ -216,9 +321,14 @@ void __hwasan_init() {
hwasan_inited = 1;
}
-void __hwasan_print_shadow(const void *x, uptr size) {
- // FIXME:
- Printf("FIXME: __hwasan_print_shadow unimplemented\n");
+void __hwasan_print_shadow(const void *p, uptr sz) {
+ uptr ptr_raw = UntagAddr(reinterpret_cast<uptr>(p));
+ uptr shadow_first = MemToShadow(ptr_raw);
+ uptr shadow_last = MemToShadow(ptr_raw + sz - 1);
+ Printf("HWASan shadow map for %zx .. %zx (pointer tag %x)\n", ptr_raw,
+ ptr_raw + sz, GetTagFromPointer((uptr)p));
+ for (uptr s = shadow_first; s <= shadow_last; ++s)
+ Printf(" %zx: %x\n", ShadowToMem(s), *(tag_t *)s);
}
sptr __hwasan_test_shadow(const void *p, uptr sz) {
@@ -227,12 +337,12 @@ sptr __hwasan_test_shadow(const void *p, uptr sz) {
tag_t ptr_tag = GetTagFromPointer((uptr)p);
if (ptr_tag == 0)
return -1;
- uptr ptr_raw = GetAddressFromPointer((uptr)p);
- uptr shadow_first = MEM_TO_SHADOW(ptr_raw);
- uptr shadow_last = MEM_TO_SHADOW(ptr_raw + sz - 1);
+ uptr ptr_raw = UntagAddr(reinterpret_cast<uptr>(p));
+ uptr shadow_first = MemToShadow(ptr_raw);
+ uptr shadow_last = MemToShadow(ptr_raw + sz - 1);
for (uptr s = shadow_first; s <= shadow_last; ++s)
if (*(tag_t*)s != ptr_tag)
- return SHADOW_TO_MEM(s) - ptr_raw;
+ return ShadowToMem(s) - ptr_raw;
return -1;
}
@@ -255,63 +365,6 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
*p = x;
}
-template<unsigned X>
-__attribute__((always_inline))
-static void SigTrap(uptr p) {
-#if defined(__aarch64__)
- (void)p;
- // 0x900 is added to do not interfere with the kernel use of lower values of
- // brk immediate.
- // FIXME: Add a constraint to put the pointer into x0, the same as x86 branch.
- asm("brk %0\n\t" ::"n"(0x900 + X));
-#elif defined(__x86_64__)
- // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
- // total. The pointer is passed via rdi.
- // 0x40 is added as a safeguard, to help distinguish our trap from others and
- // to avoid 0 offsets in the command (otherwise it'll be reduced to a
- // different nop command, the three bytes one).
- asm volatile(
- "int3\n"
- "nopl %c0(%%rax)\n"
- :: "n"(0x40 + X), "D"(p));
-#else
- // FIXME: not always sigill.
- __builtin_trap();
-#endif
- // __builtin_unreachable();
-}
-
-enum class ErrorAction { Abort, Recover };
-enum class AccessType { Load, Store };
-
-template <ErrorAction EA, AccessType AT, unsigned LogSize>
-__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
- tag_t ptr_tag = GetTagFromPointer(p);
- uptr ptr_raw = p & ~kAddressTagMask;
- tag_t mem_tag = *(tag_t *)MEM_TO_SHADOW(ptr_raw);
- if (UNLIKELY(ptr_tag != mem_tag)) {
- SigTrap<0x20 * (EA == ErrorAction::Recover) +
- 0x10 * (AT == AccessType::Store) + LogSize>(p);
- if (EA == ErrorAction::Abort) __builtin_unreachable();
- }
-}
-
-template <ErrorAction EA, AccessType AT>
-__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
- uptr sz) {
- CHECK_NE(0, sz);
- tag_t ptr_tag = GetTagFromPointer(p);
- uptr ptr_raw = p & ~kAddressTagMask;
- tag_t *shadow_first = (tag_t *)MEM_TO_SHADOW(ptr_raw);
- tag_t *shadow_last = (tag_t *)MEM_TO_SHADOW(ptr_raw + sz - 1);
- for (tag_t *t = shadow_first; t <= shadow_last; ++t)
- if (UNLIKELY(ptr_tag != *t)) {
- SigTrap<0x20 * (EA == ErrorAction::Recover) +
- 0x10 * (AT == AccessType::Store) + 0xf>(p);
- if (EA == ErrorAction::Abort) __builtin_unreachable();
- }
-}
-
void __hwasan_loadN(uptr p, uptr sz) {
CheckAddressSized<ErrorAction::Abort, AccessType::Load>(p, sz);
}
@@ -392,10 +445,38 @@ void __hwasan_tag_memory(uptr p, u8 tag, uptr sz) {
TagMemoryAligned(p, sz, tag);
}
+uptr __hwasan_tag_pointer(uptr p, u8 tag) {
+ return AddTagToPointer(p, tag);
+}
+
+void __hwasan_handle_longjmp(const void *sp_dst) {
+ uptr dst = (uptr)sp_dst;
+ // HWASan does not support tagged SP.
+ CHECK(GetTagFromPointer(dst) == 0);
+
+ uptr sp = (uptr)__builtin_frame_address(0);
+ static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M
+ if (dst < sp || dst - sp > kMaxExpectedCleanupSize) {
+ Report(
+ "WARNING: HWASan is ignoring requested __hwasan_handle_longjmp: "
+ "stack top: %p; target %p; distance: %p (%zd)\n"
+ "False positive error reports may follow\n",
+ (void *)sp, (void *)dst, dst - sp);
+ return;
+ }
+ TagMemory(sp, dst - sp, 0);
+}
+
+void __hwasan_print_memory_usage() {
+ InternalScopedString s(kMemoryUsageBufferSize);
+ HwasanFormatMemoryUsage(s);
+ Printf("%s\n", s.data());
+}
+
static const u8 kFallbackTag = 0xBB;
u8 __hwasan_generate_tag() {
- HwasanThread *t = GetCurrentThread();
+ Thread *t = GetCurrentThread();
if (!t) return kFallbackTag;
return t->GenerateRandomTag();
}
diff --git a/lib/hwasan/hwasan.h b/lib/hwasan/hwasan.h
index 47d1d057a0dd..ce9e904c5c69 100644
--- a/lib/hwasan/hwasan.h
+++ b/lib/hwasan/hwasan.h
@@ -30,6 +30,10 @@
# define HWASAN_CONTAINS_UBSAN CAN_SANITIZE_UB
#endif
+#ifndef HWASAN_WITH_INTERCEPTORS
+#define HWASAN_WITH_INTERCEPTORS 0
+#endif
+
typedef u8 tag_t;
// TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address
@@ -37,16 +41,21 @@ typedef u8 tag_t;
const unsigned kAddressTagShift = 56;
const uptr kAddressTagMask = 0xFFUL << kAddressTagShift;
+// Minimal alignment of the shadow base address. Determines the space available
+// for threads and stack histories. This is an ABI constant.
+const unsigned kShadowBaseAlignment = 32;
+
static inline tag_t GetTagFromPointer(uptr p) {
return p >> kAddressTagShift;
}
-static inline uptr GetAddressFromPointer(uptr p) {
- return p & ~kAddressTagMask;
+static inline uptr UntagAddr(uptr tagged_addr) {
+ return tagged_addr & ~kAddressTagMask;
}
-static inline void * GetAddressFromPointer(const void *p) {
- return (void *)((uptr)p & ~kAddressTagMask);
+static inline void *UntagPtr(const void *tagged_ptr) {
+ return reinterpret_cast<void *>(
+ UntagAddr(reinterpret_cast<uptr>(tagged_ptr)));
}
static inline uptr AddTagToPointer(uptr p, tag_t tag) {
@@ -61,12 +70,13 @@ extern int hwasan_report_count;
bool ProtectRange(uptr beg, uptr end);
bool InitShadow();
+void InitThreads();
+void MadviseShadow();
char *GetProcSelfMaps();
void InitializeInterceptors();
void HwasanAllocatorInit();
void HwasanAllocatorThreadFinish();
-void HwasanDeallocate(StackTrace *stack, void *ptr);
void *hwasan_malloc(uptr size, StackTrace *stack);
void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack);
@@ -77,11 +87,13 @@ void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack);
void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack);
int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
StackTrace *stack);
+void hwasan_free(void *ptr, StackTrace *stack);
void InstallTrapHandler();
void InstallAtExitHandler();
const char *GetStackOriginDescr(u32 id, uptr *pc);
+const char *GetStackFrameDescr(uptr pc);
void EnterSymbolizer();
void ExitSymbolizer();
@@ -92,8 +104,6 @@ struct SymbolizerScope {
~SymbolizerScope() { ExitSymbolizer(); }
};
-void PrintWarning(uptr pc, uptr bp);
-
void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
void *context, bool request_fast_unwind);
@@ -135,13 +145,17 @@ class ScopedThreadLocalStateBackup {
u64 va_arg_overflow_size_tls;
};
-void HwasanTSDInit(void (*destructor)(void *tsd));
-void *HwasanTSDGet();
-void HwasanTSDSet(void *tsd);
-void HwasanTSDDtor(void *tsd);
+void HwasanTSDInit();
+void HwasanTSDThreadInit();
void HwasanOnDeadlySignal(int signo, void *info, void *context);
+void UpdateMemoryUsage();
+
+void AppendToErrorMessageBuffer(const char *buffer);
+
+void AndroidTestTlsSlot();
+
} // namespace __hwasan
#define HWASAN_MALLOC_HOOK(ptr, size) \
diff --git a/lib/hwasan/hwasan_allocator.cc b/lib/hwasan/hwasan_allocator.cc
index c2b9b0b69589..8487ed7e1e55 100644
--- a/lib/hwasan/hwasan_allocator.cc
+++ b/lib/hwasan/hwasan_allocator.cc
@@ -12,10 +12,6 @@
// HWAddressSanitizer allocator.
//===----------------------------------------------------------------------===//
-#include "sanitizer_common/sanitizer_allocator.h"
-#include "sanitizer_common/sanitizer_allocator_checks.h"
-#include "sanitizer_common/sanitizer_allocator_interface.h"
-#include "sanitizer_common/sanitizer_allocator_report.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
@@ -23,30 +19,53 @@
#include "hwasan_allocator.h"
#include "hwasan_mapping.h"
#include "hwasan_thread.h"
-#include "hwasan_poisoning.h"
+#include "hwasan_report.h"
+
+#if HWASAN_WITH_INTERCEPTORS
+DEFINE_REAL(void *, realloc, void *ptr, uptr size)
+DEFINE_REAL(void, free, void *ptr)
+#endif
namespace __hwasan {
-enum {
- CHUNK_INVALID = 0,
- CHUNK_FREE = 1,
- CHUNK_ALLOCATED = 2
-};
+static Allocator allocator;
+static AllocatorCache fallback_allocator_cache;
+static SpinMutex fallback_mutex;
+static atomic_uint8_t hwasan_allocator_tagging_enabled;
+
+static const tag_t kFallbackAllocTag = 0xBB;
+static const tag_t kFallbackFreeTag = 0xBC;
-struct Metadata {
- u64 state : 2;
- u64 requested_size : 62;
- u32 alloc_context_id;
- u32 free_context_id;
+enum RightAlignMode {
+ kRightAlignNever,
+ kRightAlignSometimes,
+ kRightAlignAlways
};
-bool HwasanChunkView::IsValid() const {
- return metadata_ && metadata_->state != CHUNK_INVALID;
-}
+// These two variables are initialized from flags()->malloc_align_right
+// in HwasanAllocatorInit and are never changed afterwards.
+static RightAlignMode right_align_mode = kRightAlignNever;
+static bool right_align_8 = false;
+
+// Initialized in HwasanAllocatorInit, an never changed.
+static ALIGNED(16) u8 tail_magic[kShadowAlignment];
+
bool HwasanChunkView::IsAllocated() const {
- return metadata_ && metadata_->state == CHUNK_ALLOCATED;
+ return metadata_ && metadata_->alloc_context_id && metadata_->requested_size;
+}
+
+// Aligns the 'addr' right to the granule boundary.
+static uptr AlignRight(uptr addr, uptr requested_size) {
+ uptr tail_size = requested_size % kShadowAlignment;
+ if (!tail_size) return addr;
+ if (right_align_8)
+ return tail_size > 8 ? addr : addr + 8;
+ return addr + kShadowAlignment - tail_size;
}
+
uptr HwasanChunkView::Beg() const {
+ if (metadata_ && metadata_->right_aligned)
+ return AlignRight(block_, metadata_->requested_size);
return block_;
}
uptr HwasanChunkView::End() const {
@@ -58,88 +77,79 @@ uptr HwasanChunkView::UsedSize() const {
u32 HwasanChunkView::GetAllocStackId() const {
return metadata_->alloc_context_id;
}
-u32 HwasanChunkView::GetFreeStackId() const {
- return metadata_->free_context_id;
-}
-
-struct HwasanMapUnmapCallback {
- void OnMap(uptr p, uptr size) const {}
- void OnUnmap(uptr p, uptr size) const {
- // We are about to unmap a chunk of user memory.
- // It can return as user-requested mmap() or another thread stack.
- // Make it accessible with zero-tagged pointer.
- TagMemory(p, size, 0);
- }
-};
-#if !defined(__aarch64__) && !defined(__x86_64__)
-#error Unsupported platform
-#endif
-
-static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
-static const uptr kRegionSizeLog = 20;
-static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
-typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
-
-struct AP32 {
- static const uptr kSpaceBeg = 0;
- static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
- static const uptr kMetadataSize = sizeof(Metadata);
- typedef __sanitizer::CompactSizeClassMap SizeClassMap;
- static const uptr kRegionSizeLog = __hwasan::kRegionSizeLog;
- typedef __hwasan::ByteMap ByteMap;
- typedef HwasanMapUnmapCallback MapUnmapCallback;
- static const uptr kFlags = 0;
-};
-typedef SizeClassAllocator32<AP32> PrimaryAllocator;
-typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
-typedef LargeMmapAllocator<HwasanMapUnmapCallback> SecondaryAllocator;
-typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
- SecondaryAllocator> Allocator;
+uptr HwasanChunkView::ActualSize() const {
+ return allocator.GetActuallyAllocatedSize(reinterpret_cast<void *>(block_));
+}
-static Allocator allocator;
-static AllocatorCache fallback_allocator_cache;
-static SpinMutex fallback_mutex;
-static atomic_uint8_t hwasan_allocator_tagging_enabled;
+bool HwasanChunkView::FromSmallHeap() const {
+ return allocator.FromPrimary(reinterpret_cast<void *>(block_));
+}
-static const tag_t kFallbackAllocTag = 0xBB;
-static const tag_t kFallbackFreeTag = 0xBC;
+void GetAllocatorStats(AllocatorStatCounters s) {
+ allocator.GetStats(s);
+}
void HwasanAllocatorInit() {
atomic_store_relaxed(&hwasan_allocator_tagging_enabled,
!flags()->disable_allocator_tagging);
SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
+ switch (flags()->malloc_align_right) {
+ case 0: break;
+ case 1:
+ right_align_mode = kRightAlignSometimes;
+ right_align_8 = false;
+ break;
+ case 2:
+ right_align_mode = kRightAlignAlways;
+ right_align_8 = false;
+ break;
+ case 8:
+ right_align_mode = kRightAlignSometimes;
+ right_align_8 = true;
+ break;
+ case 9:
+ right_align_mode = kRightAlignAlways;
+ right_align_8 = true;
+ break;
+ default:
+ Report("ERROR: unsupported value of malloc_align_right flag: %d\n",
+ flags()->malloc_align_right);
+ Die();
+ }
+ for (uptr i = 0; i < kShadowAlignment; i++)
+ tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
}
-AllocatorCache *GetAllocatorCache(HwasanThreadLocalMallocStorage *ms) {
- CHECK(ms);
- CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache));
- return reinterpret_cast<AllocatorCache *>(ms->allocator_cache);
+void AllocatorSwallowThreadLocalCache(AllocatorCache *cache) {
+ allocator.SwallowCache(cache);
}
-void HwasanThreadLocalMallocStorage::CommitBack() {
- allocator.SwallowCache(GetAllocatorCache(this));
+static uptr TaggedSize(uptr size) {
+ if (!size) size = 1;
+ uptr new_size = RoundUpTo(size, kShadowAlignment);
+ CHECK_GE(new_size, size);
+ return new_size;
}
-static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,
- bool zeroise) {
- alignment = Max(alignment, kShadowAlignment);
- size = RoundUpTo(size, kShadowAlignment);
-
- if (size > kMaxAllowedMallocSize) {
+static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
+ bool zeroise) {
+ if (orig_size > kMaxAllowedMallocSize) {
if (AllocatorMayReturnNull()) {
Report("WARNING: HWAddressSanitizer failed to allocate 0x%zx bytes\n",
- size);
+ orig_size);
return nullptr;
}
- ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, stack);
+ ReportAllocationSizeTooBig(orig_size, kMaxAllowedMallocSize, stack);
}
- HwasanThread *t = GetCurrentThread();
+
+ alignment = Max(alignment, kShadowAlignment);
+ uptr size = TaggedSize(orig_size);
+ Thread *t = GetCurrentThread();
void *allocated;
if (t) {
- AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
- allocated = allocator.Allocate(cache, size, alignment);
+ allocated = allocator.Allocate(t->allocator_cache(), size, alignment);
} else {
SpinMutexLock l(&fallback_mutex);
AllocatorCache *cache = &fallback_allocator_cache;
@@ -153,11 +163,18 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,
}
Metadata *meta =
reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
- meta->state = CHUNK_ALLOCATED;
- meta->requested_size = size;
+ meta->requested_size = static_cast<u32>(orig_size);
meta->alloc_context_id = StackDepotPut(*stack);
- if (zeroise)
+ meta->right_aligned = false;
+ if (zeroise) {
internal_memset(allocated, 0, size);
+ } else if (flags()->max_malloc_fill_size > 0) {
+ uptr fill_size = Min(size, (uptr)flags()->max_malloc_fill_size);
+ internal_memset(allocated, flags()->malloc_fill_byte, fill_size);
+ }
+ if (!right_align_mode)
+ internal_memcpy(reinterpret_cast<u8 *>(allocated) + orig_size, tail_magic,
+ size - orig_size);
void *user_ptr = allocated;
if (flags()->tag_in_malloc &&
@@ -165,74 +182,101 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,
user_ptr = (void *)TagMemoryAligned(
(uptr)user_ptr, size, t ? t->GenerateRandomTag() : kFallbackAllocTag);
+ if ((orig_size % kShadowAlignment) && (alignment <= kShadowAlignment) &&
+ right_align_mode) {
+ uptr as_uptr = reinterpret_cast<uptr>(user_ptr);
+ if (right_align_mode == kRightAlignAlways ||
+ GetTagFromPointer(as_uptr) & 1) { // use a tag bit as a random bit.
+ user_ptr = reinterpret_cast<void *>(AlignRight(as_uptr, orig_size));
+ meta->right_aligned = 1;
+ }
+ }
+
HWASAN_MALLOC_HOOK(user_ptr, size);
return user_ptr;
}
-void HwasanDeallocate(StackTrace *stack, void *user_ptr) {
- CHECK(user_ptr);
- HWASAN_FREE_HOOK(user_ptr);
+static bool PointerAndMemoryTagsMatch(void *tagged_ptr) {
+ CHECK(tagged_ptr);
+ tag_t ptr_tag = GetTagFromPointer(reinterpret_cast<uptr>(tagged_ptr));
+ tag_t mem_tag = *reinterpret_cast<tag_t *>(
+ MemToShadow(reinterpret_cast<uptr>(UntagPtr(tagged_ptr))));
+ return ptr_tag == mem_tag;
+}
+
+static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
+ CHECK(tagged_ptr);
+ HWASAN_FREE_HOOK(tagged_ptr);
+
+ if (!PointerAndMemoryTagsMatch(tagged_ptr))
+ ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
+
+ void *untagged_ptr = UntagPtr(tagged_ptr);
+ void *aligned_ptr = reinterpret_cast<void *>(
+ RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
+ Metadata *meta =
+ reinterpret_cast<Metadata *>(allocator.GetMetaData(aligned_ptr));
+ uptr orig_size = meta->requested_size;
+ u32 free_context_id = StackDepotPut(*stack);
+ u32 alloc_context_id = meta->alloc_context_id;
+
+ // Check tail magic.
+ uptr tagged_size = TaggedSize(orig_size);
+ if (flags()->free_checks_tail_magic && !right_align_mode && orig_size) {
+ uptr tail_size = tagged_size - orig_size;
+ CHECK_LT(tail_size, kShadowAlignment);
+ void *tail_beg = reinterpret_cast<void *>(
+ reinterpret_cast<uptr>(aligned_ptr) + orig_size);
+ if (tail_size && internal_memcmp(tail_beg, tail_magic, tail_size))
+ ReportTailOverwritten(stack, reinterpret_cast<uptr>(tagged_ptr),
+ orig_size, tail_size, tail_magic);
+ }
- void *p = GetAddressFromPointer(user_ptr);
- Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p));
- uptr size = meta->requested_size;
- meta->state = CHUNK_FREE;
meta->requested_size = 0;
- meta->free_context_id = StackDepotPut(*stack);
+ meta->alloc_context_id = 0;
// This memory will not be reused by anyone else, so we are free to keep it
// poisoned.
- HwasanThread *t = GetCurrentThread();
+ Thread *t = GetCurrentThread();
+ if (flags()->max_free_fill_size > 0) {
+ uptr fill_size =
+ Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size);
+ internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size);
+ }
if (flags()->tag_in_free &&
atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
- TagMemoryAligned((uptr)p, size,
+ TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size),
t ? t->GenerateRandomTag() : kFallbackFreeTag);
if (t) {
- AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
- allocator.Deallocate(cache, p);
+ allocator.Deallocate(t->allocator_cache(), aligned_ptr);
+ if (auto *ha = t->heap_allocations())
+ ha->push({reinterpret_cast<uptr>(tagged_ptr), alloc_context_id,
+ free_context_id, static_cast<u32>(orig_size)});
} else {
SpinMutexLock l(&fallback_mutex);
AllocatorCache *cache = &fallback_allocator_cache;
- allocator.Deallocate(cache, p);
+ allocator.Deallocate(cache, aligned_ptr);
}
}
-void *HwasanReallocate(StackTrace *stack, void *user_old_p, uptr new_size,
- uptr alignment) {
- alignment = Max(alignment, kShadowAlignment);
- new_size = RoundUpTo(new_size, kShadowAlignment);
-
- void *old_p = GetAddressFromPointer(user_old_p);
- Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p));
- uptr old_size = meta->requested_size;
- uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p);
- if (new_size <= actually_allocated_size) {
- // We are not reallocating here.
- // FIXME: update stack trace for the allocation?
- meta->requested_size = new_size;
- if (!atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
- return user_old_p;
- if (flags()->retag_in_realloc) {
- HwasanThread *t = GetCurrentThread();
- return (void *)TagMemoryAligned(
- (uptr)old_p, new_size,
- t ? t->GenerateRandomTag() : kFallbackAllocTag);
- }
- if (new_size > old_size) {
- tag_t tag = GetTagFromPointer((uptr)user_old_p);
- TagMemoryAligned((uptr)old_p + old_size, new_size - old_size, tag);
- }
- return user_old_p;
+static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old,
+ uptr new_size, uptr alignment) {
+ if (!PointerAndMemoryTagsMatch(tagged_ptr_old))
+ ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr_old));
+
+ void *tagged_ptr_new =
+ HwasanAllocate(stack, new_size, alignment, false /*zeroise*/);
+ if (tagged_ptr_old && tagged_ptr_new) {
+ void *untagged_ptr_old = UntagPtr(tagged_ptr_old);
+ Metadata *meta =
+ reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr_old));
+ internal_memcpy(UntagPtr(tagged_ptr_new), untagged_ptr_old,
+ Min(new_size, static_cast<uptr>(meta->requested_size)));
+ HwasanDeallocate(stack, tagged_ptr_old);
}
- uptr memcpy_size = Min(new_size, old_size);
- void *new_p = HwasanAllocate(stack, new_size, alignment, false /*zeroise*/);
- if (new_p) {
- internal_memcpy(new_p, old_p, memcpy_size);
- HwasanDeallocate(stack, old_p);
- }
- return new_p;
+ return tagged_ptr_new;
}
-void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
+static void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
if (AllocatorMayReturnNull())
return nullptr;
@@ -250,12 +294,18 @@ HwasanChunkView FindHeapChunkByAddress(uptr address) {
return HwasanChunkView(reinterpret_cast<uptr>(block), metadata);
}
-static uptr AllocationSize(const void *user_ptr) {
- const void *p = GetAddressFromPointer(user_ptr);
- if (!p) return 0;
- const void *beg = allocator.GetBlockBegin(p);
- if (beg != p) return 0;
- Metadata *b = (Metadata *)allocator.GetMetaData(p);
+static uptr AllocationSize(const void *tagged_ptr) {
+ const void *untagged_ptr = UntagPtr(tagged_ptr);
+ if (!untagged_ptr) return 0;
+ const void *beg = allocator.GetBlockBegin(untagged_ptr);
+ Metadata *b = (Metadata *)allocator.GetMetaData(untagged_ptr);
+ if (b->right_aligned) {
+ if (beg != reinterpret_cast<void *>(RoundDownTo(
+ reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment)))
+ return 0;
+ } else {
+ if (beg != untagged_ptr) return 0;
+ }
return b->requested_size;
}
@@ -270,6 +320,14 @@ void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) {
if (!ptr)
return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false));
+
+#if HWASAN_WITH_INTERCEPTORS
+ // A tag of 0 means that this is a system allocator allocation, so we must use
+ // the system allocator to realloc it.
+ if (!flags()->disable_allocator_tagging && GetTagFromPointer((uptr)ptr) == 0)
+ return REAL(realloc)(ptr, size);
+#endif
+
if (size == 0) {
HwasanDeallocate(stack, ptr);
return nullptr;
@@ -331,6 +389,17 @@ int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
return 0;
}
+void hwasan_free(void *ptr, StackTrace *stack) {
+#if HWASAN_WITH_INTERCEPTORS
+ // A tag of 0 means that this is a system allocator allocation, so we must use
+ // the system allocator to free it.
+ if (!flags()->disable_allocator_tagging && GetTagFromPointer((uptr)ptr) == 0)
+ return REAL(free)(ptr);
+#endif
+
+ return HwasanDeallocate(stack, ptr);
+}
+
} // namespace __hwasan
using namespace __hwasan;
@@ -340,6 +409,15 @@ void __hwasan_enable_allocator_tagging() {
}
void __hwasan_disable_allocator_tagging() {
+#if HWASAN_WITH_INTERCEPTORS
+ // Allocator tagging must be enabled for the system allocator fallback to work
+ // correctly. This means that we can't disable it at runtime if it was enabled
+ // at startup since that might result in our deallocations going to the system
+ // allocator. If tagging was disabled at startup we avoid this problem by
+ // disabling the fallback altogether.
+ CHECK(flags()->disable_allocator_tagging);
+#endif
+
atomic_store_relaxed(&hwasan_allocator_tagging_enabled, 0);
}
diff --git a/lib/hwasan/hwasan_allocator.h b/lib/hwasan/hwasan_allocator.h
index d025112e9773..6ab722fa6bef 100644
--- a/lib/hwasan/hwasan_allocator.h
+++ b/lib/hwasan/hwasan_allocator.h
@@ -1,4 +1,4 @@
-//===-- hwasan_allocator.h ----------------------------------------*- C++ -*-===//
+//===-- hwasan_allocator.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,35 +14,73 @@
#ifndef HWASAN_ALLOCATOR_H
#define HWASAN_ALLOCATOR_H
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_checks.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_allocator_report.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_ring_buffer.h"
+#include "hwasan_poisoning.h"
+
+#if !defined(__aarch64__) && !defined(__x86_64__)
+#error Unsupported platform
+#endif
+
+#if HWASAN_WITH_INTERCEPTORS
+DECLARE_REAL(void *, realloc, void *ptr, uptr size)
+DECLARE_REAL(void, free, void *ptr)
+#endif
namespace __hwasan {
-struct HwasanThreadLocalMallocStorage {
- uptr quarantine_cache[16];
- // Allocator cache contains atomic_uint64_t which must be 8-byte aligned.
- ALIGNED(8) uptr allocator_cache[96 * (512 * 8 + 16)]; // Opaque.
- void CommitBack();
+struct Metadata {
+ u32 requested_size : 31; // sizes are < 2G.
+ u32 right_aligned : 1;
+ u32 alloc_context_id;
+};
- private:
- // These objects are allocated via mmap() and are zero-initialized.
- HwasanThreadLocalMallocStorage() {}
+struct HwasanMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const { UpdateMemoryUsage(); }
+ void OnUnmap(uptr p, uptr size) const {
+ // We are about to unmap a chunk of user memory.
+ // It can return as user-requested mmap() or another thread stack.
+ // Make it accessible with zero-tagged pointer.
+ TagMemory(p, size, 0);
+ }
};
-struct Metadata;
+static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
+
+struct AP64 {
+ static const uptr kSpaceBeg = ~0ULL;
+ static const uptr kSpaceSize = 0x2000000000ULL;
+ static const uptr kMetadataSize = sizeof(Metadata);
+ typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
+ using AddressSpaceView = LocalAddressSpaceView;
+ typedef HwasanMapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags = 0;
+};
+typedef SizeClassAllocator64<AP64> PrimaryAllocator;
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef LargeMmapAllocator<HwasanMapUnmapCallback> SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
+ SecondaryAllocator> Allocator;
+
+void AllocatorSwallowThreadLocalCache(AllocatorCache *cache);
class HwasanChunkView {
public:
HwasanChunkView() : block_(0), metadata_(nullptr) {}
HwasanChunkView(uptr block, Metadata *metadata)
: block_(block), metadata_(metadata) {}
- bool IsValid() const; // Checks if it points to a valid allocated chunk
bool IsAllocated() const; // Checks if the memory is currently allocated
uptr Beg() const; // First byte of user memory
uptr End() const; // Last byte of user memory
uptr UsedSize() const; // Size requested by the user
+ uptr ActualSize() const; // Size allocated by the allocator.
u32 GetAllocStackId() const;
- u32 GetFreeStackId() const;
+ bool FromSmallHeap() const;
private:
uptr block_;
Metadata *const metadata_;
@@ -50,6 +88,21 @@ class HwasanChunkView {
HwasanChunkView FindHeapChunkByAddress(uptr address);
+// Information about one (de)allocation that happened in the past.
+// These are recorded in a thread-local ring buffer.
+// TODO: this is currently 24 bytes (20 bytes + alignment).
+// Compress it to 16 bytes or extend it to be more useful.
+struct HeapAllocationRecord {
+ uptr tagged_addr;
+ u32 alloc_context_id;
+ u32 free_context_id;
+ u32 requested_size;
+};
+
+typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
+
+void GetAllocatorStats(AllocatorStatCounters s);
+
} // namespace __hwasan
#endif // HWASAN_ALLOCATOR_H
diff --git a/lib/hwasan/hwasan_checks.h b/lib/hwasan/hwasan_checks.h
new file mode 100644
index 000000000000..688b5e2bed82
--- /dev/null
+++ b/lib/hwasan/hwasan_checks.h
@@ -0,0 +1,80 @@
+//===-- hwasan_checks.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of HWAddressSanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef HWASAN_CHECKS_H
+#define HWASAN_CHECKS_H
+
+#include "hwasan_mapping.h"
+
+namespace __hwasan {
+template <unsigned X>
+__attribute__((always_inline)) static void SigTrap(uptr p) {
+#if defined(__aarch64__)
+ (void)p;
+ // 0x900 is added to do not interfere with the kernel use of lower values of
+ // brk immediate.
+ // FIXME: Add a constraint to put the pointer into x0, the same as x86 branch.
+ asm("brk %0\n\t" ::"n"(0x900 + X));
+#elif defined(__x86_64__)
+ // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
+ // total. The pointer is passed via rdi.
+ // 0x40 is added as a safeguard, to help distinguish our trap from others and
+ // to avoid 0 offsets in the command (otherwise it'll be reduced to a
+ // different nop command, the three bytes one).
+ asm volatile(
+ "int3\n"
+ "nopl %c0(%%rax)\n" ::"n"(0x40 + X),
+ "D"(p));
+#else
+ // FIXME: not always sigill.
+ __builtin_trap();
+#endif
+ // __builtin_unreachable();
+}
+
+enum class ErrorAction { Abort, Recover };
+enum class AccessType { Load, Store };
+
+template <ErrorAction EA, AccessType AT, unsigned LogSize>
+__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
+ tag_t ptr_tag = GetTagFromPointer(p);
+ uptr ptr_raw = p & ~kAddressTagMask;
+ tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
+ if (UNLIKELY(ptr_tag != mem_tag)) {
+ SigTrap<0x20 * (EA == ErrorAction::Recover) +
+ 0x10 * (AT == AccessType::Store) + LogSize>(p);
+ if (EA == ErrorAction::Abort)
+ __builtin_unreachable();
+ }
+}
+
+template <ErrorAction EA, AccessType AT>
+__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
+ uptr sz) {
+ if (sz == 0)
+ return;
+ tag_t ptr_tag = GetTagFromPointer(p);
+ uptr ptr_raw = p & ~kAddressTagMask;
+ tag_t *shadow_first = (tag_t *)MemToShadow(ptr_raw);
+ tag_t *shadow_last = (tag_t *)MemToShadow(ptr_raw + sz - 1);
+ for (tag_t *t = shadow_first; t <= shadow_last; ++t)
+ if (UNLIKELY(ptr_tag != *t)) {
+ SigTrap<0x20 * (EA == ErrorAction::Recover) +
+ 0x10 * (AT == AccessType::Store) + 0xf>(p);
+ if (EA == ErrorAction::Abort)
+ __builtin_unreachable();
+ }
+}
+} // end namespace __hwasan
+
+#endif // HWASAN_CHECKS_H
diff --git a/lib/hwasan/hwasan_dynamic_shadow.cc b/lib/hwasan/hwasan_dynamic_shadow.cc
index 17338003aa65..87670f508283 100644
--- a/lib/hwasan/hwasan_dynamic_shadow.cc
+++ b/lib/hwasan/hwasan_dynamic_shadow.cc
@@ -13,6 +13,7 @@
///
//===----------------------------------------------------------------------===//
+#include "hwasan.h"
#include "hwasan_dynamic_shadow.h"
#include "hwasan_mapping.h"
#include "sanitizer_common/sanitizer_common.h"
@@ -35,12 +36,16 @@ static void UnmapFromTo(uptr from, uptr to) {
}
}
-// Returns an address aligned to 8 pages, such that one page on the left and
-// shadow_size_bytes bytes on the right of it are mapped r/o.
+// Returns an address aligned to kShadowBaseAlignment, such that
+// 2**kShadowBaseAlingment on the left and shadow_size_bytes bytes on the right
+// of it are mapped no access.
static uptr MapDynamicShadow(uptr shadow_size_bytes) {
const uptr granularity = GetMmapGranularity();
- const uptr alignment = granularity * SHADOW_GRANULARITY;
- const uptr left_padding = granularity;
+ const uptr min_alignment = granularity << kShadowScale;
+ const uptr alignment = 1ULL << kShadowBaseAlignment;
+ CHECK_GE(alignment, min_alignment);
+
+ const uptr left_padding = 1ULL << kShadowBaseAlignment;
const uptr shadow_size =
RoundUpTo(shadow_size_bytes, granularity);
const uptr map_size = shadow_size + left_padding + alignment;
@@ -58,8 +63,7 @@ static uptr MapDynamicShadow(uptr shadow_size_bytes) {
} // namespace __hwasan
-#if HWASAN_PREMAP_SHADOW
-
+#if SANITIZER_ANDROID
extern "C" {
INTERFACE_ATTRIBUTE void __hwasan_shadow();
@@ -117,16 +121,22 @@ void __hwasan_shadow();
} // extern "C"
-#endif // HWASAN_PREMAP_SHADOW
-
namespace __hwasan {
uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
-#if HWASAN_PREMAP_SHADOW
if (IsPremapShadowAvailable())
return FindPremappedShadowStart(shadow_size_bytes);
-#endif
return MapDynamicShadow(shadow_size_bytes);
}
} // namespace __hwasan
+#else
+namespace __hwasan {
+
+uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
+ return MapDynamicShadow(shadow_size_bytes);
+}
+
+} // namespace __hwasan
+#
+#endif // SANITIZER_ANDROID
diff --git a/lib/hwasan/hwasan_flags.h b/lib/hwasan/hwasan_flags.h
index 16d60c4d8ba5..492d5bb98c27 100644
--- a/lib/hwasan/hwasan_flags.h
+++ b/lib/hwasan/hwasan_flags.h
@@ -1,4 +1,4 @@
-//===-- hwasan_flags.h --------------------------------------------*- C++ -*-===//
+//===-- hwasan_flags.h ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/hwasan/hwasan_flags.inc b/lib/hwasan/hwasan_flags.inc
index c45781168d6c..b450ab9503f9 100644
--- a/lib/hwasan/hwasan_flags.inc
+++ b/lib/hwasan/hwasan_flags.inc
@@ -17,9 +17,10 @@
// HWASAN_FLAG(Type, Name, DefaultValue, Description)
// See COMMON_FLAG in sanitizer_flags.inc for more details.
+HWASAN_FLAG(bool, verbose_threads, false,
+ "inform on thread creation/destruction")
HWASAN_FLAG(bool, tag_in_malloc, true, "")
HWASAN_FLAG(bool, tag_in_free, true, "")
-HWASAN_FLAG(bool, retag_in_realloc, true, "")
HWASAN_FLAG(bool, print_stats, false, "")
HWASAN_FLAG(bool, halt_on_error, true, "")
HWASAN_FLAG(bool, atexit, false, "")
@@ -31,3 +32,57 @@ HWASAN_FLAG(bool, disable_allocator_tagging, false, "")
// If false, use simple increment of a thread local counter to generate new
// tags.
HWASAN_FLAG(bool, random_tags, true, "")
+
+HWASAN_FLAG(
+ int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K.
+ "HWASan allocator flag. max_malloc_fill_size is the maximal amount of "
+ "bytes that will be filled with malloc_fill_byte on malloc.")
+
+// Rules for malloc alignment on aarch64:
+// * If the size is 16-aligned, then malloc should return 16-aligned memory.
+// * Otherwise, malloc should return 8-alignment memory.
+// So,
+// * If the size is 16-aligned, we don't need to do anything.
+// * Otherwise we don't have to obey 16-alignment, just the 8-alignment.
+// * We may want to break the 8-alignment rule to catch more buffer overflows
+// but this will break valid code in some rare cases, like this:
+// struct Foo {
+// // accessed via atomic instructions that require 8-alignment.
+// std::atomic<int64_t> atomic_stuff;
+// ...
+// char vla[1]; // the actual size of vla could be anything.
+// }
+// Which means that the safe values for malloc_align_right are 0, 8, 9,
+// and the values 1 and 2 may require changes in otherwise valid code.
+
+HWASAN_FLAG(
+ int, malloc_align_right, 0, // off by default
+ "HWASan allocator flag. "
+ "0 (default): allocations are always aligned left to 16-byte boundary; "
+ "1: allocations are sometimes aligned right to 1-byte boundary (risky); "
+ "2: allocations are always aligned right to 1-byte boundary (risky); "
+ "8: allocations are sometimes aligned right to 8-byte boundary; "
+ "9: allocations are always aligned right to 8-byte boundary."
+ )
+HWASAN_FLAG(bool, free_checks_tail_magic, 1,
+ "If set, free() will check the magic values "
+ "to the right of the allocated object "
+ "if the allocation size is not a divident of the granule size")
+HWASAN_FLAG(
+ int, max_free_fill_size, 0,
+ "HWASan allocator flag. max_free_fill_size is the maximal amount of "
+ "bytes that will be filled with free_fill_byte during free.")
+HWASAN_FLAG(int, malloc_fill_byte, 0xbe,
+ "Value used to fill the newly allocated memory.")
+HWASAN_FLAG(int, free_fill_byte, 0x55,
+ "Value used to fill deallocated memory.")
+HWASAN_FLAG(int, heap_history_size, 1023,
+ "The number of heap (de)allocations remembered per thread. "
+ "Affects the quality of heap-related reports, but not the ability "
+ "to find bugs.")
+HWASAN_FLAG(bool, export_memory_stats, true,
+ "Export up-to-date memory stats through /proc")
+HWASAN_FLAG(int, stack_history_size, 1024,
+ "The number of stack frames remembered per thread. "
+ "Affects the quality of stack-related reports, but not the ability "
+ "to find bugs.")
diff --git a/lib/hwasan/hwasan_interceptors.cc b/lib/hwasan/hwasan_interceptors.cc
index 66aab95db56f..fb0dcb8905c0 100644
--- a/lib/hwasan/hwasan_interceptors.cc
+++ b/lib/hwasan/hwasan_interceptors.cc
@@ -1,4 +1,4 @@
-//===-- hwasan_interceptors.cc ----------------------------------------------===//
+//===-- hwasan_interceptors.cc --------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -17,6 +17,7 @@
#include "interception/interception.h"
#include "hwasan.h"
+#include "hwasan_allocator.h"
#include "hwasan_mapping.h"
#include "hwasan_thread.h"
#include "hwasan_poisoning.h"
@@ -44,24 +45,19 @@ using __sanitizer::atomic_load;
using __sanitizer::atomic_store;
using __sanitizer::atomic_uintptr_t;
-DECLARE_REAL(SIZE_T, strlen, const char *s)
-DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen)
-DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
-DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
-
bool IsInInterceptorScope() {
- HwasanThread *t = GetCurrentThread();
+ Thread *t = GetCurrentThread();
return t && t->InInterceptorScope();
}
struct InterceptorScope {
InterceptorScope() {
- HwasanThread *t = GetCurrentThread();
+ Thread *t = GetCurrentThread();
if (t)
t->EnterInterceptorScope();
}
~InterceptorScope() {
- HwasanThread *t = GetCurrentThread();
+ Thread *t = GetCurrentThread();
if (t)
t->LeaveInterceptorScope();
}
@@ -92,66 +88,24 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) {
} while (0)
-
-#define HWASAN_READ_RANGE(ctx, offset, size) \
- CHECK_UNPOISONED(offset, size)
-#define HWASAN_WRITE_RANGE(ctx, offset, size) \
- CHECK_UNPOISONED(offset, size)
-
-
-
-// Check that [x, x+n) range is unpoisoned.
-#define CHECK_UNPOISONED_0(x, n) \
- do { \
- sptr __offset = __hwasan_test_shadow(x, n); \
- if (__hwasan::IsInSymbolizer()) break; \
- if (__offset >= 0) { \
- GET_CALLER_PC_BP_SP; \
- (void)sp; \
- ReportInvalidAccessInsideAddressRange(__func__, x, n, __offset); \
- __hwasan::PrintWarning(pc, bp); \
- if (__hwasan::flags()->halt_on_error) { \
- Printf("Exiting\n"); \
- Die(); \
- } \
- } \
- } while (0)
-
-// Check that [x, x+n) range is unpoisoned unless we are in a nested
-// interceptor.
-#define CHECK_UNPOISONED(x, n) \
- do { \
- if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
- } while (0)
-
-#define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n) \
- CHECK_UNPOISONED((x), \
- common_flags()->strict_string_checks ? (len) + 1 : (n) )
-
-
-INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
+int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size) {
GET_MALLOC_STACK_TRACE;
CHECK_NE(memptr, 0);
int res = hwasan_posix_memalign(memptr, alignment, size, &stack);
return res;
}
-#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
-INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) {
+void * __sanitizer_memalign(uptr alignment, uptr size) {
GET_MALLOC_STACK_TRACE;
return hwasan_memalign(alignment, size, &stack);
}
-#define HWASAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
-#else
-#define HWASAN_MAYBE_INTERCEPT_MEMALIGN
-#endif
-INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) {
+void * __sanitizer_aligned_alloc(uptr alignment, uptr size) {
GET_MALLOC_STACK_TRACE;
return hwasan_aligned_alloc(alignment, size, &stack);
}
-INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) {
+void * __sanitizer___libc_memalign(uptr alignment, uptr size) {
GET_MALLOC_STACK_TRACE;
void *ptr = hwasan_memalign(alignment, size, &stack);
if (ptr)
@@ -159,80 +113,47 @@ INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) {
return ptr;
}
-INTERCEPTOR(void *, valloc, SIZE_T size) {
+void * __sanitizer_valloc(uptr size) {
GET_MALLOC_STACK_TRACE;
return hwasan_valloc(size, &stack);
}
-#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
-INTERCEPTOR(void *, pvalloc, SIZE_T size) {
+void * __sanitizer_pvalloc(uptr size) {
GET_MALLOC_STACK_TRACE;
return hwasan_pvalloc(size, &stack);
}
-#define HWASAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
-#else
-#define HWASAN_MAYBE_INTERCEPT_PVALLOC
-#endif
-INTERCEPTOR(void, free, void *ptr) {
+void __sanitizer_free(void *ptr) {
GET_MALLOC_STACK_TRACE;
if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
- HwasanDeallocate(&stack, ptr);
+ hwasan_free(ptr, &stack);
}
-#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
-INTERCEPTOR(void, cfree, void *ptr) {
+void __sanitizer_cfree(void *ptr) {
GET_MALLOC_STACK_TRACE;
if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return;
- HwasanDeallocate(&stack, ptr);
+ hwasan_free(ptr, &stack);
}
-#define HWASAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
-#else
-#define HWASAN_MAYBE_INTERCEPT_CFREE
-#endif
-INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
+uptr __sanitizer_malloc_usable_size(const void *ptr) {
return __sanitizer_get_allocated_size(ptr);
}
-#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
-// This function actually returns a struct by value, but we can't unpoison a
-// temporary! The following is equivalent on all supported platforms but
-// aarch64 (which uses a different register for sret value). We have a test
-// to confirm that.
-INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) {
-#ifdef __aarch64__
- uptr r8;
- asm volatile("mov %0,x8" : "=r" (r8));
- sret = reinterpret_cast<__sanitizer_mallinfo*>(r8);
-#endif
- REAL(memset)(sret, 0, sizeof(*sret));
+struct __sanitizer_struct_mallinfo __sanitizer_mallinfo() {
+ __sanitizer_struct_mallinfo sret;
+ internal_memset(&sret, 0, sizeof(sret));
+ return sret;
}
-#define HWASAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
-#else
-#define HWASAN_MAYBE_INTERCEPT_MALLINFO
-#endif
-#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
-INTERCEPTOR(int, mallopt, int cmd, int value) {
- return -1;
+int __sanitizer_mallopt(int cmd, int value) {
+ return 0;
}
-#define HWASAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
-#else
-#define HWASAN_MAYBE_INTERCEPT_MALLOPT
-#endif
-#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
-INTERCEPTOR(void, malloc_stats, void) {
+void __sanitizer_malloc_stats(void) {
// FIXME: implement, but don't call REAL(malloc_stats)!
}
-#define HWASAN_MAYBE_INTERCEPT_MALLOC_STATS INTERCEPT_FUNCTION(malloc_stats)
-#else
-#define HWASAN_MAYBE_INTERCEPT_MALLOC_STATS
-#endif
-
-INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
+void * __sanitizer_calloc(uptr nmemb, uptr size) {
GET_MALLOC_STACK_TRACE;
if (UNLIKELY(!hwasan_inited))
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
@@ -240,7 +161,7 @@ INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) {
return hwasan_calloc(nmemb, size, &stack);
}
-INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
+void * __sanitizer_realloc(void *ptr, uptr size) {
GET_MALLOC_STACK_TRACE;
if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
@@ -258,7 +179,7 @@ INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
return hwasan_realloc(ptr, size, &stack);
}
-INTERCEPTOR(void *, malloc, SIZE_T size) {
+void * __sanitizer_malloc(uptr size) {
GET_MALLOC_STACK_TRACE;
if (UNLIKELY(!hwasan_init_is_running))
ENSURE_HWASAN_INITED();
@@ -268,48 +189,44 @@ INTERCEPTOR(void *, malloc, SIZE_T size) {
return hwasan_malloc(size, &stack);
}
-template <class Mmap>
-static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T sz, int prot,
- int flags, int fd, OFF64_T off) {
- if (addr && !MEM_IS_APP(addr)) {
- if (flags & map_fixed) {
- errno = errno_EINVAL;
- return (void *)-1;
- } else {
- addr = nullptr;
- }
- }
- return real_mmap(addr, sz, prot, flags, fd, off);
-}
-
-extern "C" int pthread_attr_init(void *attr);
-extern "C" int pthread_attr_destroy(void *attr);
-
-static void *HwasanThreadStartFunc(void *arg) {
- HwasanThread *t = (HwasanThread *)arg;
- SetCurrentThread(t);
- return t->ThreadStart();
-}
-
-INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
- void * param) {
- ENSURE_HWASAN_INITED(); // for GetTlsSize()
- __sanitizer_pthread_attr_t myattr;
- if (!attr) {
- pthread_attr_init(&myattr);
- attr = &myattr;
- }
+#if HWASAN_WITH_INTERCEPTORS
+#define INTERCEPTOR_ALIAS(RET, FN, ARGS...) \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE RET WRAP(FN)(ARGS) \
+ ALIAS("__sanitizer_" #FN); \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE RET FN( \
+ ARGS) ALIAS("__sanitizer_" #FN)
+
+INTERCEPTOR_ALIAS(int, posix_memalign, void **memptr, SIZE_T alignment,
+ SIZE_T size);
+INTERCEPTOR_ALIAS(void *, aligned_alloc, SIZE_T alignment, SIZE_T size);
+INTERCEPTOR_ALIAS(void *, __libc_memalign, SIZE_T alignment, SIZE_T size);
+INTERCEPTOR_ALIAS(void *, valloc, SIZE_T size);
+INTERCEPTOR_ALIAS(void, free, void *ptr);
+INTERCEPTOR_ALIAS(uptr, malloc_usable_size, const void *ptr);
+INTERCEPTOR_ALIAS(void *, calloc, SIZE_T nmemb, SIZE_T size);
+INTERCEPTOR_ALIAS(void *, realloc, void *ptr, SIZE_T size);
+INTERCEPTOR_ALIAS(void *, malloc, SIZE_T size);
- AdjustStackSize(attr);
-
- HwasanThread *t = HwasanThread::Create(callback, param);
+#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
+INTERCEPTOR_ALIAS(void *, memalign, SIZE_T alignment, SIZE_T size);
+INTERCEPTOR_ALIAS(void *, pvalloc, SIZE_T size);
+INTERCEPTOR_ALIAS(void, cfree, void *ptr);
+INTERCEPTOR_ALIAS(__sanitizer_struct_mallinfo, mallinfo);
+INTERCEPTOR_ALIAS(int, mallopt, int cmd, int value);
+INTERCEPTOR_ALIAS(void, malloc_stats, void);
+#endif
+#endif // HWASAN_WITH_INTERCEPTORS
- int res = REAL(pthread_create)(th, attr, HwasanThreadStartFunc, t);
- if (attr == &myattr)
- pthread_attr_destroy(&myattr);
+#if HWASAN_WITH_INTERCEPTORS && !defined(__aarch64__)
+INTERCEPTOR(int, pthread_create, void *th, void *attr,
+ void *(*callback)(void *), void *param) {
+ ScopedTaggingDisabler disabler;
+ int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
+ callback, param);
return res;
}
+#endif
static void BeforeFork() {
StackDepotLockAll();
@@ -341,137 +258,21 @@ int OnExit() {
} // namespace __hwasan
-// A version of CHECK_UNPOISONED using a saved scope value. Used in common
-// interceptors.
-#define CHECK_UNPOISONED_CTX(ctx, x, n) \
- do { \
- if (!((HwasanInterceptorContext *)ctx)->in_interceptor_scope) \
- CHECK_UNPOISONED_0(x, n); \
- } while (0)
-
-#define HWASAN_INTERCEPT_FUNC(name) \
- do { \
- if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
- VReport(1, "HWAddressSanitizer: failed to intercept '" #name "'\n"); \
- } while (0)
-
-#define HWASAN_INTERCEPT_FUNC_VER(name, ver) \
- do { \
- if ((!INTERCEPT_FUNCTION_VER(name, ver) || !REAL(name))) \
- VReport( \
- 1, "HWAddressSanitizer: failed to intercept '" #name "@@" #ver "'\n"); \
- } while (0)
-
-#define COMMON_INTERCEPT_FUNCTION(name) HWASAN_INTERCEPT_FUNC(name)
-#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
- HWASAN_INTERCEPT_FUNC_VER(name, ver)
-#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
- CHECK_UNPOISONED_CTX(ctx, ptr, size)
-#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
- CHECK_UNPOISONED_CTX(ctx, ptr, size)
-#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \
- HWASAN_WRITE_RANGE(ctx, ptr, size)
-#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
- if (hwasan_init_is_running) return REAL(func)(__VA_ARGS__); \
- ENSURE_HWASAN_INITED(); \
- HwasanInterceptorContext hwasan_ctx = {IsInInterceptorScope()}; \
- ctx = (void *)&hwasan_ctx; \
- (void)ctx; \
- InterceptorScope interceptor_scope;
-#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
- do { \
- } while (false)
-#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
- do { \
- } while (false)
-#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
- do { \
- } while (false)
-#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
- do { \
- } while (false)
-#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
- do { \
- } while (false) // FIXME
-#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
- do { \
- } while (false) // FIXME
-#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
-#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
-
-#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
- if (HwasanThread *t = GetCurrentThread()) { \
- *begin = t->tls_begin(); \
- *end = t->tls_end(); \
- } else { \
- *begin = *end = 0; \
- }
-
-#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \
- { \
- COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size); \
- if (common_flags()->intercept_intrin && \
- MEM_IS_APP(GetAddressFromPointer(dst))) \
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
- return REAL(memset)(dst, v, size); \
- }
-
-#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, fd, \
- offset) \
- do { \
- return mmap_interceptor(REAL(mmap), addr, length, prot, flags, fd, \
- offset); \
- } while (false)
-
-#include "sanitizer_common/sanitizer_platform_interceptors.h"
-#include "sanitizer_common/sanitizer_common_interceptors.inc"
-#include "sanitizer_common/sanitizer_signal_interceptors.inc"
-
-#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
-#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
- do { \
- (void)(p); \
- (void)(s); \
- } while (false)
-#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
- do { \
- (void)(p); \
- (void)(s); \
- } while (false)
-#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
- do { \
- (void)(p); \
- (void)(s); \
- } while (false)
-#include "sanitizer_common/sanitizer_common_syscalls.inc"
-#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
-
-
-
namespace __hwasan {
void InitializeInterceptors() {
static int inited = 0;
CHECK_EQ(inited, 0);
- InitializeCommonInterceptors();
- InitializeSignalInterceptors();
-
- INTERCEPT_FUNCTION(posix_memalign);
- HWASAN_MAYBE_INTERCEPT_MEMALIGN;
- INTERCEPT_FUNCTION(__libc_memalign);
- INTERCEPT_FUNCTION(valloc);
- HWASAN_MAYBE_INTERCEPT_PVALLOC;
- INTERCEPT_FUNCTION(malloc);
- INTERCEPT_FUNCTION(calloc);
+
+ INTERCEPT_FUNCTION(fork);
+
+#if HWASAN_WITH_INTERCEPTORS
+#if !defined(__aarch64__)
+ INTERCEPT_FUNCTION(pthread_create);
+#endif
INTERCEPT_FUNCTION(realloc);
INTERCEPT_FUNCTION(free);
- HWASAN_MAYBE_INTERCEPT_CFREE;
- INTERCEPT_FUNCTION(malloc_usable_size);
- HWASAN_MAYBE_INTERCEPT_MALLINFO;
- HWASAN_MAYBE_INTERCEPT_MALLOPT;
- HWASAN_MAYBE_INTERCEPT_MALLOC_STATS;
- INTERCEPT_FUNCTION(pthread_create);
- INTERCEPT_FUNCTION(fork);
+#endif
inited = 1;
}
diff --git a/lib/hwasan/hwasan_interface_internal.h b/lib/hwasan/hwasan_interface_internal.h
index b4e5c80904df..d3b2087d03c6 100644
--- a/lib/hwasan/hwasan_interface_internal.h
+++ b/lib/hwasan/hwasan_interface_internal.h
@@ -1,4 +1,4 @@
-//===-- hwasan_interface_internal.h -------------------------------*- C++ -*-===//
+//===-- hwasan_interface_internal.h -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -16,10 +16,14 @@
#define HWASAN_INTERFACE_INTERNAL_H
#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_shadow_init();
+
+SANITIZER_INTERFACE_ATTRIBUTE
void __hwasan_init();
using __sanitizer::uptr;
@@ -33,6 +37,9 @@ using __sanitizer::u16;
using __sanitizer::u8;
SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_init_frames(uptr, uptr);
+
+SANITIZER_INTERFACE_ATTRIBUTE
extern uptr __hwasan_shadow_memory_dynamic_address;
SANITIZER_INTERFACE_ATTRIBUTE
@@ -91,6 +98,9 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __hwasan_tag_memory(uptr p, u8 tag, uptr sz);
SANITIZER_INTERFACE_ATTRIBUTE
+uptr __hwasan_tag_pointer(uptr p, u8 tag);
+
+SANITIZER_INTERFACE_ATTRIBUTE
u8 __hwasan_generate_tag();
// Returns the offset of the first tag mismatch or -1 if the whole range is
@@ -105,6 +115,9 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __hwasan_print_shadow(const void *x, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_handle_longjmp(const void *sp_dst);
+
+SANITIZER_INTERFACE_ATTRIBUTE
u16 __sanitizer_unaligned_load16(const uu16 *p);
SANITIZER_INTERFACE_ATTRIBUTE
@@ -128,6 +141,66 @@ void __hwasan_enable_allocator_tagging();
SANITIZER_INTERFACE_ATTRIBUTE
void __hwasan_disable_allocator_tagging();
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_thread_enter();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_thread_exit();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_print_memory_usage();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void * __sanitizer_memalign(uptr alignment, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void * __sanitizer_aligned_alloc(uptr alignment, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void * __sanitizer___libc_memalign(uptr alignment, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void * __sanitizer_valloc(uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void * __sanitizer_pvalloc(uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_free(void *ptr);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_cfree(void *ptr);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_malloc_usable_size(const void *ptr);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+__hwasan::__sanitizer_struct_mallinfo __sanitizer_mallinfo();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __sanitizer_mallopt(int cmd, int value);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_malloc_stats(void);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void * __sanitizer_calloc(uptr nmemb, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void * __sanitizer_realloc(void *ptr, uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void * __sanitizer_malloc(uptr size);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__hwasan_memcpy(void *dst, const void *src, uptr size);
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__hwasan_memset(void *s, int c, uptr n);
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__hwasan_memmove(void *dest, const void *src, uptr n);
} // extern "C"
#endif // HWASAN_INTERFACE_INTERNAL_H
diff --git a/lib/hwasan/hwasan_linux.cc b/lib/hwasan/hwasan_linux.cc
index 5ab98dca594d..5b0a8b4ac98f 100644
--- a/lib/hwasan/hwasan_linux.cc
+++ b/lib/hwasan/hwasan_linux.cc
@@ -22,7 +22,9 @@
#include "hwasan_mapping.h"
#include "hwasan_report.h"
#include "hwasan_thread.h"
+#include "hwasan_thread_list.h"
+#include <dlfcn.h>
#include <elf.h>
#include <link.h>
#include <pthread.h>
@@ -37,6 +39,11 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_procmaps.h"
+#if HWASAN_WITH_INTERCEPTORS && !SANITIZER_ANDROID
+SANITIZER_INTERFACE_ATTRIBUTE
+THREADLOCAL uptr __hwasan_tls;
+#endif
+
namespace __hwasan {
static void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
@@ -51,8 +58,6 @@ static void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
size);
Abort();
}
- if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size);
- if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
}
static void ProtectGap(uptr addr, uptr size) {
@@ -103,55 +108,31 @@ static void PrintAddressSpaceLayout() {
else
CHECK_EQ(kHighShadowEnd + 1, kHighMemStart);
PrintRange(kHighShadowStart, kHighShadowEnd, "HighShadow");
- if (SHADOW_OFFSET) {
- if (kLowShadowEnd + 1 < kHighShadowStart)
- PrintRange(kLowShadowEnd + 1, kHighShadowStart - 1, "ShadowGap");
- else
- CHECK_EQ(kLowMemEnd + 1, kHighShadowStart);
- PrintRange(kLowShadowStart, kLowShadowEnd, "LowShadow");
- if (kLowMemEnd + 1 < kLowShadowStart)
- PrintRange(kLowMemEnd + 1, kLowShadowStart - 1, "ShadowGap");
- else
- CHECK_EQ(kLowMemEnd + 1, kLowShadowStart);
- PrintRange(kLowMemStart, kLowMemEnd, "LowMem");
- CHECK_EQ(0, kLowMemStart);
- } else {
- if (kLowMemEnd + 1 < kHighShadowStart)
- PrintRange(kLowMemEnd + 1, kHighShadowStart - 1, "ShadowGap");
- else
- CHECK_EQ(kLowMemEnd + 1, kHighShadowStart);
- PrintRange(kLowMemStart, kLowMemEnd, "LowMem");
- CHECK_EQ(kLowShadowEnd + 1, kLowMemStart);
- PrintRange(kLowShadowStart, kLowShadowEnd, "LowShadow");
- PrintRange(0, kLowShadowStart - 1, "ShadowGap");
- }
+ if (kLowShadowEnd + 1 < kHighShadowStart)
+ PrintRange(kLowShadowEnd + 1, kHighShadowStart - 1, "ShadowGap");
+ else
+ CHECK_EQ(kLowMemEnd + 1, kHighShadowStart);
+ PrintRange(kLowShadowStart, kLowShadowEnd, "LowShadow");
+ if (kLowMemEnd + 1 < kLowShadowStart)
+ PrintRange(kLowMemEnd + 1, kLowShadowStart - 1, "ShadowGap");
+ else
+ CHECK_EQ(kLowMemEnd + 1, kLowShadowStart);
+ PrintRange(kLowMemStart, kLowMemEnd, "LowMem");
+ CHECK_EQ(0, kLowMemStart);
}
static uptr GetHighMemEnd() {
// HighMem covers the upper part of the address space.
uptr max_address = GetMaxUserVirtualAddress();
- if (SHADOW_OFFSET)
- // Adjust max address to make sure that kHighMemEnd and kHighMemStart are
- // properly aligned:
- max_address |= SHADOW_GRANULARITY * GetMmapGranularity() - 1;
+ // Adjust max address to make sure that kHighMemEnd and kHighMemStart are
+ // properly aligned:
+ max_address |= (GetMmapGranularity() << kShadowScale) - 1;
return max_address;
}
static void InitializeShadowBaseAddress(uptr shadow_size_bytes) {
- // Set the shadow memory address to uninitialized.
- __hwasan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
- uptr shadow_start = SHADOW_OFFSET;
- // Detect if a dynamic shadow address must be used and find the available
- // location when necessary. When dynamic address is used, the macro
- // kLowShadowBeg expands to __hwasan_shadow_memory_dynamic_address which
- // was just set to kDefaultShadowSentinel.
- if (shadow_start == kDefaultShadowSentinel) {
- __hwasan_shadow_memory_dynamic_address = 0;
- CHECK_EQ(0, SHADOW_OFFSET);
- shadow_start = FindDynamicShadowStart(shadow_size_bytes);
- }
- // Update the shadow memory address (potentially) used by instrumentation.
- __hwasan_shadow_memory_dynamic_address = shadow_start;
+ __hwasan_shadow_memory_dynamic_address =
+ FindDynamicShadowStart(shadow_size_bytes);
}
bool InitShadow() {
@@ -159,29 +140,23 @@ bool InitShadow() {
kHighMemEnd = GetHighMemEnd();
// Determine shadow memory base offset.
- InitializeShadowBaseAddress(MEM_TO_SHADOW_SIZE(kHighMemEnd));
+ InitializeShadowBaseAddress(MemToShadowSize(kHighMemEnd));
// Place the low memory first.
- if (SHADOW_OFFSET) {
- kLowMemEnd = SHADOW_OFFSET - 1;
- kLowMemStart = 0;
- } else {
- // LowMem covers as much of the first 4GB as possible.
- kLowMemEnd = (1UL << 32) - 1;
- kLowMemStart = MEM_TO_SHADOW(kLowMemEnd) + 1;
- }
+ kLowMemEnd = __hwasan_shadow_memory_dynamic_address - 1;
+ kLowMemStart = 0;
// Define the low shadow based on the already placed low memory.
- kLowShadowEnd = MEM_TO_SHADOW(kLowMemEnd);
- kLowShadowStart = SHADOW_OFFSET ? SHADOW_OFFSET : MEM_TO_SHADOW(kLowMemStart);
+ kLowShadowEnd = MemToShadow(kLowMemEnd);
+ kLowShadowStart = __hwasan_shadow_memory_dynamic_address;
// High shadow takes whatever memory is left up there (making sure it is not
// interfering with low memory in the fixed case).
- kHighShadowEnd = MEM_TO_SHADOW(kHighMemEnd);
- kHighShadowStart = Max(kLowMemEnd, MEM_TO_SHADOW(kHighShadowEnd)) + 1;
+ kHighShadowEnd = MemToShadow(kHighMemEnd);
+ kHighShadowStart = Max(kLowMemEnd, MemToShadow(kHighShadowEnd)) + 1;
// High memory starts where allocated shadow allows.
- kHighMemStart = SHADOW_TO_MEM(kHighShadowStart);
+ kHighMemStart = ShadowToMem(kHighShadowStart);
// Check the sanity of the defined memory ranges (there might be gaps).
CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0);
@@ -190,10 +165,7 @@ bool InitShadow() {
CHECK_GT(kHighShadowStart, kLowMemEnd);
CHECK_GT(kLowMemEnd, kLowMemStart);
CHECK_GT(kLowShadowEnd, kLowShadowStart);
- if (SHADOW_OFFSET)
- CHECK_GT(kLowShadowStart, kLowMemEnd);
- else
- CHECK_GT(kLowMemEnd, kLowShadowStart);
+ CHECK_GT(kLowShadowStart, kLowMemEnd);
if (Verbosity())
PrintAddressSpaceLayout();
@@ -204,21 +176,43 @@ bool InitShadow() {
// Protect all the gaps.
ProtectGap(0, Min(kLowMemStart, kLowShadowStart));
- if (SHADOW_OFFSET) {
- if (kLowMemEnd + 1 < kLowShadowStart)
- ProtectGap(kLowMemEnd + 1, kLowShadowStart - kLowMemEnd - 1);
- if (kLowShadowEnd + 1 < kHighShadowStart)
- ProtectGap(kLowShadowEnd + 1, kHighShadowStart - kLowShadowEnd - 1);
- } else {
- if (kLowMemEnd + 1 < kHighShadowStart)
- ProtectGap(kLowMemEnd + 1, kHighShadowStart - kLowMemEnd - 1);
- }
+ if (kLowMemEnd + 1 < kLowShadowStart)
+ ProtectGap(kLowMemEnd + 1, kLowShadowStart - kLowMemEnd - 1);
+ if (kLowShadowEnd + 1 < kHighShadowStart)
+ ProtectGap(kLowShadowEnd + 1, kHighShadowStart - kLowShadowEnd - 1);
if (kHighShadowEnd + 1 < kHighMemStart)
ProtectGap(kHighShadowEnd + 1, kHighMemStart - kHighShadowEnd - 1);
return true;
}
+void InitThreads() {
+ CHECK(__hwasan_shadow_memory_dynamic_address);
+ uptr guard_page_size = GetMmapGranularity();
+ uptr thread_space_start =
+ __hwasan_shadow_memory_dynamic_address - (1ULL << kShadowBaseAlignment);
+ uptr thread_space_end =
+ __hwasan_shadow_memory_dynamic_address - guard_page_size;
+ ReserveShadowMemoryRange(thread_space_start, thread_space_end - 1,
+ "hwasan threads");
+ ProtectGap(thread_space_end,
+ __hwasan_shadow_memory_dynamic_address - thread_space_end);
+ InitThreadList(thread_space_start, thread_space_end - thread_space_start);
+}
+
+static void MadviseShadowRegion(uptr beg, uptr end) {
+ uptr size = end - beg + 1;
+ if (common_flags()->no_huge_pages_for_shadow)
+ NoHugePagesInRegion(beg, size);
+ if (common_flags()->use_madv_dontdump)
+ DontDumpShadowMemory(beg, size);
+}
+
+void MadviseShadow() {
+ MadviseShadowRegion(kLowShadowStart, kLowShadowEnd);
+ MadviseShadowRegion(kHighShadowStart, kHighShadowEnd);
+}
+
bool MemIsApp(uptr p) {
CHECK(GetTagFromPointer(p) == 0);
return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd);
@@ -240,37 +234,81 @@ void InstallAtExitHandler() {
// ---------------------- TSD ---------------- {{{1
+extern "C" void __hwasan_thread_enter() {
+ hwasanThreadList().CreateCurrentThread();
+}
+
+extern "C" void __hwasan_thread_exit() {
+ Thread *t = GetCurrentThread();
+ // Make sure that signal handler can not see a stale current thread pointer.
+ atomic_signal_fence(memory_order_seq_cst);
+ if (t)
+ hwasanThreadList().ReleaseThread(t);
+}
+
+#if HWASAN_WITH_INTERCEPTORS
static pthread_key_t tsd_key;
static bool tsd_key_inited = false;
-void HwasanTSDInit(void (*destructor)(void *tsd)) {
+void HwasanTSDThreadInit() {
+ if (tsd_key_inited)
+ CHECK_EQ(0, pthread_setspecific(tsd_key,
+ (void *)GetPthreadDestructorIterations()));
+}
+
+void HwasanTSDDtor(void *tsd) {
+ uptr iterations = (uptr)tsd;
+ if (iterations > 1) {
+ CHECK_EQ(0, pthread_setspecific(tsd_key, (void *)(iterations - 1)));
+ return;
+ }
+ __hwasan_thread_exit();
+}
+
+void HwasanTSDInit() {
CHECK(!tsd_key_inited);
tsd_key_inited = true;
- CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
+ CHECK_EQ(0, pthread_key_create(&tsd_key, HwasanTSDDtor));
}
+#else
+void HwasanTSDInit() {}
+void HwasanTSDThreadInit() {}
+#endif
-HwasanThread *GetCurrentThread() {
- return (HwasanThread*)pthread_getspecific(tsd_key);
+#if SANITIZER_ANDROID
+uptr *GetCurrentThreadLongPtr() {
+ return (uptr *)get_android_tls_ptr();
}
-
-void SetCurrentThread(HwasanThread *t) {
- // Make sure that HwasanTSDDtor gets called at the end.
- CHECK(tsd_key_inited);
- // Make sure we do not reset the current HwasanThread.
- CHECK_EQ(0, pthread_getspecific(tsd_key));
- pthread_setspecific(tsd_key, (void *)t);
+#else
+uptr *GetCurrentThreadLongPtr() {
+ return &__hwasan_tls;
}
+#endif
-void HwasanTSDDtor(void *tsd) {
- HwasanThread *t = (HwasanThread*)tsd;
- if (t->destructor_iterations_ > 1) {
- t->destructor_iterations_--;
- CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
- return;
+#if SANITIZER_ANDROID
+void AndroidTestTlsSlot() {
+ uptr kMagicValue = 0x010203040A0B0C0D;
+ *(uptr *)get_android_tls_ptr() = kMagicValue;
+ dlerror();
+ if (*(uptr *)get_android_tls_ptr() != kMagicValue) {
+ Printf(
+ "ERROR: Incompatible version of Android: TLS_SLOT_SANITIZER(6) is used "
+ "for dlerror().\n");
+ Die();
}
- // Make sure that signal handler can not see a stale current thread pointer.
- atomic_signal_fence(memory_order_seq_cst);
- HwasanThread::TSDDtor(tsd);
+}
+#else
+void AndroidTestTlsSlot() {}
+#endif
+
+Thread *GetCurrentThread() {
+ uptr *ThreadLong = GetCurrentThreadLongPtr();
+#if HWASAN_WITH_INTERCEPTORS
+ if (!*ThreadLong)
+ __hwasan_thread_enter();
+#endif
+ auto *R = (StackAllocationsRingBuffer *)ThreadLong;
+ return hwasanThreadList().GetThreadByBufferAddress((uptr)(R->Next()));
}
struct AccessInfo {
@@ -340,14 +378,13 @@ static bool HwasanOnSIGTRAP(int signo, siginfo_t *info, ucontext_t *uc) {
BufferedStackTrace *stack = stack_buffer.data();
stack->Reset();
SignalContext sig{info, uc};
- GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, uc,
- common_flags()->fast_unwind_on_fatal);
-
- ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store);
+ GetStackTrace(stack, kStackTraceMax, StackTrace::GetNextInstructionPc(sig.pc),
+ sig.bp, uc, common_flags()->fast_unwind_on_fatal);
++hwasan_report_count;
- if (flags()->halt_on_error || !ai.recover)
- Die();
+
+ bool fatal = flags()->halt_on_error || !ai.recover;
+ ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store, fatal);
#if defined(__aarch64__)
uc->uc_mcontext.pc += 4;
@@ -360,8 +397,8 @@ static bool HwasanOnSIGTRAP(int signo, siginfo_t *info, ucontext_t *uc) {
static void OnStackUnwind(const SignalContext &sig, const void *,
BufferedStackTrace *stack) {
- GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context,
- common_flags()->fast_unwind_on_fatal);
+ GetStackTrace(stack, kStackTraceMax, StackTrace::GetNextInstructionPc(sig.pc),
+ sig.bp, sig.context, common_flags()->fast_unwind_on_fatal);
}
void HwasanOnDeadlySignal(int signo, void *info, void *context) {
diff --git a/lib/hwasan/hwasan_mapping.h b/lib/hwasan/hwasan_mapping.h
index 650a5aefcb2d..e5e23dc60337 100644
--- a/lib/hwasan/hwasan_mapping.h
+++ b/lib/hwasan/hwasan_mapping.h
@@ -16,68 +16,41 @@
#define HWASAN_MAPPING_H
#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "hwasan_interface_internal.h"
-// Typical mapping on Linux/x86_64 with fixed shadow mapping:
-// || [0x080000000000, 0x7fffffffffff] || HighMem ||
-// || [0x008000000000, 0x07ffffffffff] || HighShadow ||
-// || [0x000100000000, 0x007fffffffff] || ShadowGap ||
-// || [0x000010000000, 0x0000ffffffff] || LowMem ||
-// || [0x000001000000, 0x00000fffffff] || LowShadow ||
-// || [0x000000000000, 0x000000ffffff] || ShadowGap ||
-//
-// and with dynamic shadow mapped at [0x770d59f40000, 0x7f0d59f40000]:
+// Typical mapping on Linux/x86_64:
+// with dynamic shadow mapped at [0x770d59f40000, 0x7f0d59f40000]:
// || [0x7f0d59f40000, 0x7fffffffffff] || HighMem ||
// || [0x7efe2f934000, 0x7f0d59f3ffff] || HighShadow ||
// || [0x7e7e2f934000, 0x7efe2f933fff] || ShadowGap ||
// || [0x770d59f40000, 0x7e7e2f933fff] || LowShadow ||
// || [0x000000000000, 0x770d59f3ffff] || LowMem ||
-// Typical mapping on Android/AArch64 (39-bit VMA):
-// || [0x001000000000, 0x007fffffffff] || HighMem ||
-// || [0x000800000000, 0x000fffffffff] || ShadowGap ||
-// || [0x000100000000, 0x0007ffffffff] || HighShadow ||
-// || [0x000010000000, 0x0000ffffffff] || LowMem ||
-// || [0x000001000000, 0x00000fffffff] || LowShadow ||
-// || [0x000000000000, 0x000000ffffff] || ShadowGap ||
-//
-// and with dynamic shadow mapped: [0x007477480000, 0x007c77480000]:
+// Typical mapping on Android/AArch64
+// with dynamic shadow mapped: [0x007477480000, 0x007c77480000]:
// || [0x007c77480000, 0x007fffffffff] || HighMem ||
// || [0x007c3ebc8000, 0x007c7747ffff] || HighShadow ||
// || [0x007bbebc8000, 0x007c3ebc7fff] || ShadowGap ||
// || [0x007477480000, 0x007bbebc7fff] || LowShadow ||
// || [0x000000000000, 0x00747747ffff] || LowMem ||
-static constexpr __sanitizer::u64 kDefaultShadowSentinel = ~(__sanitizer::u64)0;
-
// Reasonable values are 4 (for 1/16th shadow) and 6 (for 1/64th).
-constexpr __sanitizer::uptr kShadowScale = 4;
-constexpr __sanitizer::uptr kShadowAlignment = 1ULL << kShadowScale;
-
-#if SANITIZER_ANDROID
-# define HWASAN_FIXED_MAPPING 0
-#else
-# define HWASAN_FIXED_MAPPING 1
-#endif
-
-#if HWASAN_FIXED_MAPPING
-# define SHADOW_OFFSET (0)
-# define HWASAN_PREMAP_SHADOW 0
-#else
-# define SHADOW_OFFSET (__hwasan_shadow_memory_dynamic_address)
-# define HWASAN_PREMAP_SHADOW 1
-#endif
-
-#define SHADOW_GRANULARITY (1ULL << kShadowScale)
-
-#define MEM_TO_SHADOW(mem) (((uptr)(mem) >> kShadowScale) + SHADOW_OFFSET)
-#define SHADOW_TO_MEM(shadow) (((uptr)(shadow) - SHADOW_OFFSET) << kShadowScale)
-
-#define MEM_TO_SHADOW_SIZE(size) ((uptr)(size) >> kShadowScale)
-
-#define MEM_IS_APP(mem) MemIsApp((uptr)(mem))
+constexpr uptr kShadowScale = 4;
+constexpr uptr kShadowAlignment = 1ULL << kShadowScale;
namespace __hwasan {
+inline uptr MemToShadow(uptr untagged_addr) {
+ return (untagged_addr >> kShadowScale) +
+ __hwasan_shadow_memory_dynamic_address;
+}
+inline uptr ShadowToMem(uptr shadow_addr) {
+ return (shadow_addr - __hwasan_shadow_memory_dynamic_address) << kShadowScale;
+}
+inline uptr MemToShadowSize(uptr size) {
+ return size >> kShadowScale;
+}
+
bool MemIsApp(uptr p);
} // namespace __hwasan
diff --git a/lib/hwasan/hwasan_memintrinsics.cc b/lib/hwasan/hwasan_memintrinsics.cc
new file mode 100644
index 000000000000..9cb844e45c40
--- /dev/null
+++ b/lib/hwasan/hwasan_memintrinsics.cc
@@ -0,0 +1,45 @@
+//===-- hwasan_memintrinsics.cc ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file is a part of HWAddressSanitizer and contains HWASAN versions of
+/// memset, memcpy and memmove
+///
+//===----------------------------------------------------------------------===//
+
+#include <string.h>
+#include "hwasan.h"
+#include "hwasan_checks.h"
+#include "hwasan_flags.h"
+#include "hwasan_interface_internal.h"
+#include "sanitizer_common/sanitizer_libc.h"
+
+using namespace __hwasan;
+
+void *__hwasan_memset(void *block, int c, uptr size) {
+ CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
+ reinterpret_cast<uptr>(block), size);
+ return memset(UntagPtr(block), c, size);
+}
+
+void *__hwasan_memcpy(void *to, const void *from, uptr size) {
+ CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
+ reinterpret_cast<uptr>(to), size);
+ CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
+ reinterpret_cast<uptr>(from), size);
+ return memcpy(UntagPtr(to), UntagPtr(from), size);
+}
+
+void *__hwasan_memmove(void *to, const void *from, uptr size) {
+ CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
+ reinterpret_cast<uptr>(to), size);
+ CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
+ reinterpret_cast<uptr>(from), size);
+ return memmove(UntagPtr(to), UntagPtr(from), size);
+}
diff --git a/lib/hwasan/hwasan_new_delete.cc b/lib/hwasan/hwasan_new_delete.cc
index 63ca74edd481..f2e8faf5da73 100644
--- a/lib/hwasan/hwasan_new_delete.cc
+++ b/lib/hwasan/hwasan_new_delete.cc
@@ -51,7 +51,7 @@ void *operator new[](size_t size, std::nothrow_t const&) {
#define OPERATOR_DELETE_BODY \
GET_MALLOC_STACK_TRACE; \
- if (ptr) HwasanDeallocate(&stack, ptr)
+ if (ptr) hwasan_free(ptr, &stack)
INTERCEPTOR_ATTRIBUTE
void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
diff --git a/lib/hwasan/hwasan_poisoning.cc b/lib/hwasan/hwasan_poisoning.cc
index b99d8ed0be79..9c8e16b12ad5 100644
--- a/lib/hwasan/hwasan_poisoning.cc
+++ b/lib/hwasan/hwasan_poisoning.cc
@@ -1,4 +1,4 @@
-//===-- hwasan_poisoning.cc ---------------------------------------*- C++ -*-===//
+//===-- hwasan_poisoning.cc -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -22,8 +22,8 @@ namespace __hwasan {
uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) {
CHECK(IsAligned(p, kShadowAlignment));
CHECK(IsAligned(size, kShadowAlignment));
- uptr shadow_start = MEM_TO_SHADOW(p);
- uptr shadow_size = MEM_TO_SHADOW_SIZE(size);
+ uptr shadow_start = MemToShadow(p);
+ uptr shadow_size = MemToShadowSize(size);
internal_memset((void *)shadow_start, tag, shadow_size);
return AddTagToPointer(p, tag);
}
diff --git a/lib/hwasan/hwasan_poisoning.h b/lib/hwasan/hwasan_poisoning.h
index b44a91f975f5..0dbf9d8ed4ef 100644
--- a/lib/hwasan/hwasan_poisoning.h
+++ b/lib/hwasan/hwasan_poisoning.h
@@ -1,4 +1,4 @@
-//===-- hwasan_poisoning.h ----------------------------------------*- C++ -*-===//
+//===-- hwasan_poisoning.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/hwasan/hwasan_report.cc b/lib/hwasan/hwasan_report.cc
index 16e9016ea35b..ea3e4096daef 100644
--- a/lib/hwasan/hwasan_report.cc
+++ b/lib/hwasan/hwasan_report.cc
@@ -15,18 +15,64 @@
#include "hwasan.h"
#include "hwasan_allocator.h"
#include "hwasan_mapping.h"
+#include "hwasan_thread.h"
+#include "hwasan_thread_list.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
using namespace __sanitizer;
namespace __hwasan {
+class ScopedReport {
+ public:
+ ScopedReport(bool fatal = false) : error_message_(1), fatal(fatal) {
+ BlockingMutexLock lock(&error_message_lock_);
+ error_message_ptr_ = fatal ? &error_message_ : nullptr;
+ }
+
+ ~ScopedReport() {
+ BlockingMutexLock lock(&error_message_lock_);
+ if (fatal) {
+ SetAbortMessage(error_message_.data());
+ Die();
+ }
+ error_message_ptr_ = nullptr;
+ }
+
+ static void MaybeAppendToErrorMessage(const char *msg) {
+ BlockingMutexLock lock(&error_message_lock_);
+ if (!error_message_ptr_)
+ return;
+ uptr len = internal_strlen(msg);
+ uptr old_size = error_message_ptr_->size();
+ error_message_ptr_->resize(old_size + len);
+ // overwrite old trailing '\0', keep new trailing '\0' untouched.
+ internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len);
+ }
+ private:
+ ScopedErrorReportLock error_report_lock_;
+ InternalMmapVector<char> error_message_;
+ bool fatal;
+
+ static InternalMmapVector<char> *error_message_ptr_;
+ static BlockingMutex error_message_lock_;
+};
+
+InternalMmapVector<char> *ScopedReport::error_message_ptr_;
+BlockingMutex ScopedReport::error_message_lock_;
+
+// If there is an active ScopedReport, append to its error message.
+void AppendToErrorMessageBuffer(const char *buffer) {
+ ScopedReport::MaybeAppendToErrorMessage(buffer);
+}
+
static StackTrace GetStackTraceFromId(u32 id) {
CHECK(id);
StackTrace res = StackDepotGet(id);
@@ -34,100 +80,344 @@ static StackTrace GetStackTraceFromId(u32 id) {
return res;
}
+// A RAII object that holds a copy of the current thread stack ring buffer.
+// The actual stack buffer may change while we are iterating over it (for
+// example, Printf may call syslog() which can itself be built with hwasan).
+class SavedStackAllocations {
+ public:
+ SavedStackAllocations(StackAllocationsRingBuffer *rb) {
+ uptr size = rb->size() * sizeof(uptr);
+ void *storage =
+ MmapAlignedOrDieOnFatalError(size, size * 2, "saved stack allocations");
+ new (&rb_) StackAllocationsRingBuffer(*rb, storage);
+ }
+
+ ~SavedStackAllocations() {
+ StackAllocationsRingBuffer *rb = get();
+ UnmapOrDie(rb->StartOfStorage(), rb->size() * sizeof(uptr));
+ }
+
+ StackAllocationsRingBuffer *get() {
+ return (StackAllocationsRingBuffer *)&rb_;
+ }
+
+ private:
+ uptr rb_;
+};
+
class Decorator: public __sanitizer::SanitizerCommonDecorator {
public:
Decorator() : SanitizerCommonDecorator() { }
+ const char *Access() { return Blue(); }
const char *Allocation() const { return Magenta(); }
const char *Origin() const { return Magenta(); }
const char *Name() const { return Green(); }
+ const char *Location() { return Green(); }
+ const char *Thread() { return Green(); }
};
-struct HeapAddressDescription {
- uptr addr;
- u32 alloc_stack_id;
- u32 free_stack_id;
-
- void Print() const {
- Decorator d;
- if (free_stack_id) {
- Printf("%sfreed here:%s\n", d.Allocation(), d.Default());
- GetStackTraceFromId(free_stack_id).Print();
- Printf("%spreviously allocated here:%s\n", d.Allocation(), d.Default());
- } else {
- Printf("%sallocated here:%s\n", d.Allocation(), d.Default());
+// Returns the index of the rb element that matches tagged_addr (plus one),
+// or zero if found nothing.
+uptr FindHeapAllocation(HeapAllocationsRingBuffer *rb,
+ uptr tagged_addr,
+ HeapAllocationRecord *har) {
+ if (!rb) return 0;
+ for (uptr i = 0, size = rb->size(); i < size; i++) {
+ auto h = (*rb)[i];
+ if (h.tagged_addr <= tagged_addr &&
+ h.tagged_addr + h.requested_size > tagged_addr) {
+ *har = h;
+ return i + 1;
}
- GetStackTraceFromId(alloc_stack_id).Print();
}
-};
+ return 0;
+}
+
+void PrintAddressDescription(
+ uptr tagged_addr, uptr access_size,
+ StackAllocationsRingBuffer *current_stack_allocations) {
+ Decorator d;
+ int num_descriptions_printed = 0;
+ uptr untagged_addr = UntagAddr(tagged_addr);
+
+ // Print some very basic information about the address, if it's a heap.
+ HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
+ if (uptr beg = chunk.Beg()) {
+ uptr size = chunk.ActualSize();
+ Printf("%s[%p,%p) is a %s %s heap chunk; "
+ "size: %zd offset: %zd\n%s",
+ d.Location(),
+ beg, beg + size,
+ chunk.FromSmallHeap() ? "small" : "large",
+ chunk.IsAllocated() ? "allocated" : "unallocated",
+ size, untagged_addr - beg,
+ d.Default());
+ }
+
+ // Check if this looks like a heap buffer overflow by scanning
+ // the shadow left and right and looking for the first adjacent
+ // object with a different memory tag. If that tag matches addr_tag,
+ // check the allocator if it has a live chunk there.
+ tag_t addr_tag = GetTagFromPointer(tagged_addr);
+ tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
+ if (*tag_ptr != addr_tag) { // should be true usually.
+ tag_t *left = tag_ptr, *right = tag_ptr;
+ // scan left.
+ for (int i = 0; i < 1000 && *left == *tag_ptr; i++, left--){}
+ // scan right.
+ for (int i = 0; i < 1000 && *right == *tag_ptr; i++, right++){}
+ // Chose the object that has addr_tag and that is closer to addr.
+ tag_t *candidate = nullptr;
+ if (*right == addr_tag && *left == addr_tag)
+ candidate = right - tag_ptr < tag_ptr - left ? right : left;
+ else if (*right == addr_tag)
+ candidate = right;
+ else if (*left == addr_tag)
+ candidate = left;
+
+ if (candidate) {
+ uptr mem = ShadowToMem(reinterpret_cast<uptr>(candidate));
+ HwasanChunkView chunk = FindHeapChunkByAddress(mem);
+ if (chunk.IsAllocated()) {
+ Printf("%s", d.Location());
+ Printf(
+ "%p is located %zd bytes to the %s of %zd-byte region [%p,%p)\n",
+ untagged_addr,
+ candidate == left ? untagged_addr - chunk.End()
+ : chunk.Beg() - untagged_addr,
+ candidate == right ? "left" : "right", chunk.UsedSize(),
+ chunk.Beg(), chunk.End());
+ Printf("%s", d.Allocation());
+ Printf("allocated here:\n");
+ Printf("%s", d.Default());
+ GetStackTraceFromId(chunk.GetAllocStackId()).Print();
+ num_descriptions_printed++;
+ }
+ }
+ }
+
+ hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
+ // Scan all threads' ring buffers to find if it's a heap-use-after-free.
+ HeapAllocationRecord har;
+ if (uptr D = FindHeapAllocation(t->heap_allocations(), tagged_addr, &har)) {
+ Printf("%s", d.Location());
+ Printf("%p is located %zd bytes inside of %zd-byte region [%p,%p)\n",
+ untagged_addr, untagged_addr - UntagAddr(har.tagged_addr),
+ har.requested_size, UntagAddr(har.tagged_addr),
+ UntagAddr(har.tagged_addr) + har.requested_size);
+ Printf("%s", d.Allocation());
+ Printf("freed by thread T%zd here:\n", t->unique_id());
+ Printf("%s", d.Default());
+ GetStackTraceFromId(har.free_context_id).Print();
+
+ Printf("%s", d.Allocation());
+ Printf("previously allocated here:\n", t);
+ Printf("%s", d.Default());
+ GetStackTraceFromId(har.alloc_context_id).Print();
+
+ // Print a developer note: the index of this heap object
+ // in the thread's deallocation ring buffer.
+ Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", D,
+ flags()->heap_history_size);
+
+ t->Announce();
+ num_descriptions_printed++;
+ }
+
+ // Very basic check for stack memory.
+ if (t->AddrIsInStack(untagged_addr)) {
+ Printf("%s", d.Location());
+ Printf("Address %p is located in stack of thread T%zd\n", untagged_addr,
+ t->unique_id());
+ Printf("%s", d.Default());
+ t->Announce();
-bool GetHeapAddressInformation(uptr addr, uptr access_size,
- HeapAddressDescription *description) {
- HwasanChunkView chunk = FindHeapChunkByAddress(addr);
- if (!chunk.IsValid())
- return false;
- description->addr = addr;
- description->alloc_stack_id = chunk.GetAllocStackId();
- description->free_stack_id = chunk.GetFreeStackId();
- return true;
+ // Temporary report section, needs to be improved.
+ Printf("Previously allocated frames:\n");
+ auto *sa = (t == GetCurrentThread() && current_stack_allocations)
+ ? current_stack_allocations
+ : t->stack_allocations();
+ uptr frames = Min((uptr)flags()->stack_history_size, sa->size());
+ InternalScopedString frame_desc(GetPageSizeCached() * 2);
+ for (uptr i = 0; i < frames; i++) {
+ uptr record = (*sa)[i];
+ if (!record)
+ break;
+ uptr sp = (record >> 48) << 4;
+ uptr pc_mask = (1ULL << 48) - 1;
+ uptr pc = record & pc_mask;
+ if (SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc)) {
+ frame_desc.append(" sp: 0x%zx pc: %p ", sp, pc);
+ RenderFrame(&frame_desc, "in %f %s:%l\n", 0, frame->info,
+ common_flags()->symbolize_vs_style,
+ common_flags()->strip_path_prefix);
+ frame->ClearAll();
+ if (auto Descr = GetStackFrameDescr(pc))
+ frame_desc.append(" %s\n", Descr);
+ }
+ Printf("%s", frame_desc.data());
+ frame_desc.clear();
+ }
+
+ num_descriptions_printed++;
+ }
+ });
+
+ // Print the remaining threads, as an extra information, 1 line per thread.
+ hwasanThreadList().VisitAllLiveThreads([&](Thread *t) { t->Announce(); });
+
+ if (!num_descriptions_printed)
+ // We exhausted our possibilities. Bail out.
+ Printf("HWAddressSanitizer can not describe address in more detail.\n");
}
-void PrintAddressDescription(uptr addr, uptr access_size) {
- HeapAddressDescription heap_description;
- if (GetHeapAddressInformation(addr, access_size, &heap_description)) {
- heap_description.Print();
- return;
+void ReportStats() {}
+
+static void PrintTagsAroundAddr(tag_t *tag_ptr) {
+ Printf(
+ "Memory tags around the buggy address (one tag corresponds to %zd "
+ "bytes):\n", kShadowAlignment);
+
+ const uptr row_len = 16; // better be power of two.
+ const uptr num_rows = 17;
+ tag_t *center_row_beg = reinterpret_cast<tag_t *>(
+ RoundDownTo(reinterpret_cast<uptr>(tag_ptr), row_len));
+ tag_t *beg_row = center_row_beg - row_len * (num_rows / 2);
+ tag_t *end_row = center_row_beg + row_len * (num_rows / 2);
+ InternalScopedString s(GetPageSizeCached() * 8);
+ for (tag_t *row = beg_row; row < end_row; row += row_len) {
+ s.append("%s", row == center_row_beg ? "=>" : " ");
+ for (uptr i = 0; i < row_len; i++) {
+ s.append("%s", row + i == tag_ptr ? "[" : " ");
+ s.append("%02x", row[i]);
+ s.append("%s", row + i == tag_ptr ? "]" : " ");
+ }
+ s.append("%s\n", row == center_row_beg ? "<=" : " ");
}
- // We exhausted our possibilities. Bail out.
- Printf("HWAddressSanitizer can not describe address in more detail.\n");
+ Printf("%s", s.data());
}
-void ReportInvalidAccess(StackTrace *stack, u32 origin) {
- ScopedErrorReportLock l;
+void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
+ ScopedReport R(flags()->halt_on_error);
+ uptr untagged_addr = UntagAddr(tagged_addr);
+ tag_t ptr_tag = GetTagFromPointer(tagged_addr);
+ tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
+ tag_t mem_tag = *tag_ptr;
Decorator d;
- Printf("%s", d.Warning());
- Report("WARNING: HWAddressSanitizer: invalid access\n");
+ Printf("%s", d.Error());
+ uptr pc = stack->size ? stack->trace[0] : 0;
+ const char *bug_type = "invalid-free";
+ Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type,
+ untagged_addr, pc);
+ Printf("%s", d.Access());
+ Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag);
Printf("%s", d.Default());
+
stack->Print();
- ReportErrorSummary("invalid-access", stack);
-}
-void ReportStats() {}
+ PrintAddressDescription(tagged_addr, 0, nullptr);
-void ReportInvalidAccessInsideAddressRange(const char *what, const void *start,
- uptr size, uptr offset) {
- ScopedErrorReportLock l;
+ PrintTagsAroundAddr(tag_ptr);
+ ReportErrorSummary(bug_type, stack);
+}
+
+void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
+ uptr tail_size, const u8 *expected) {
+ ScopedReport R(flags()->halt_on_error);
Decorator d;
- Printf("%s", d.Warning());
- Printf("%sTag mismatch in %s%s%s at offset %zu inside [%p, %zu)%s\n",
- d.Warning(), d.Name(), what, d.Warning(), offset, start, size,
- d.Default());
- PrintAddressDescription((uptr)start + offset, 1);
- // if (__sanitizer::Verbosity())
- // DescribeMemoryRange(start, size);
+ uptr untagged_addr = UntagAddr(tagged_addr);
+ Printf("%s", d.Error());
+ const char *bug_type = "alocation-tail-overwritten";
+ Report("ERROR: %s: %s; heap object [%p,%p) of size %zd\n", SanitizerToolName,
+ bug_type, untagged_addr, untagged_addr + orig_size, orig_size);
+ Printf("\n%s", d.Default());
+ stack->Print();
+ HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
+ if (chunk.Beg()) {
+ Printf("%s", d.Allocation());
+ Printf("allocated here:\n");
+ Printf("%s", d.Default());
+ GetStackTraceFromId(chunk.GetAllocStackId()).Print();
+ }
+
+ InternalScopedString s(GetPageSizeCached() * 8);
+ CHECK_GT(tail_size, 0U);
+ CHECK_LT(tail_size, kShadowAlignment);
+ u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size);
+ s.append("Tail contains: ");
+ for (uptr i = 0; i < kShadowAlignment - tail_size; i++)
+ s.append(".. ");
+ for (uptr i = 0; i < tail_size; i++)
+ s.append("%02x ", tail[i]);
+ s.append("\n");
+ s.append("Expected: ");
+ for (uptr i = 0; i < kShadowAlignment - tail_size; i++)
+ s.append(".. ");
+ for (uptr i = 0; i < tail_size; i++)
+ s.append("%02x ", expected[i]);
+ s.append("\n");
+ s.append(" ");
+ for (uptr i = 0; i < kShadowAlignment - tail_size; i++)
+ s.append(" ");
+ for (uptr i = 0; i < tail_size; i++)
+ s.append("%s ", expected[i] != tail[i] ? "^^" : " ");
+
+ s.append("\nThis error occurs when a buffer overflow overwrites memory\n"
+ "to the right of a heap object, but within the %zd-byte granule, e.g.\n"
+ " char *x = new char[20];\n"
+ " x[25] = 42;\n"
+ "By default %s does not detect such bugs at the time of write,\n"
+ "but can detect them at the time of free/delete.\n"
+ "To disable this feature set HWASAN_OPTIONS=free_checks_tail_magic=0;\n"
+ "To enable checking at the time of access, set "
+ "HWASAN_OPTIONS=malloc_align_right to non-zero\n\n",
+ kShadowAlignment, SanitizerToolName);
+ Printf("%s", s.data());
+ GetCurrentThread()->Announce();
+
+ tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
+ PrintTagsAroundAddr(tag_ptr);
+
+ ReportErrorSummary(bug_type, stack);
}
-void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
- bool is_store) {
- ScopedErrorReportLock l;
+void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
+ bool is_store, bool fatal) {
+ ScopedReport R(fatal);
+ SavedStackAllocations current_stack_allocations(
+ GetCurrentThread()->stack_allocations());
Decorator d;
- Printf("%s", d.Warning());
- uptr address = GetAddressFromPointer(addr);
- Printf("%s of size %zu at %p\n", is_store ? "WRITE" : "READ", access_size,
- address);
-
- tag_t ptr_tag = GetTagFromPointer(addr);
- tag_t mem_tag = *(tag_t *)MEM_TO_SHADOW(address);
- Printf("pointer tag 0x%x\nmemory tag 0x%x\n", ptr_tag, mem_tag);
+ Printf("%s", d.Error());
+ uptr untagged_addr = UntagAddr(tagged_addr);
+ // TODO: when possible, try to print heap-use-after-free, etc.
+ const char *bug_type = "tag-mismatch";
+ uptr pc = stack->size ? stack->trace[0] : 0;
+ Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type,
+ untagged_addr, pc);
+
+ Thread *t = GetCurrentThread();
+
+ tag_t ptr_tag = GetTagFromPointer(tagged_addr);
+ tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
+ tag_t mem_tag = *tag_ptr;
+ Printf("%s", d.Access());
+ Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread T%zd\n",
+ is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag,
+ mem_tag, t->unique_id());
Printf("%s", d.Default());
stack->Print();
- PrintAddressDescription(address, access_size);
+ PrintAddressDescription(tagged_addr, access_size,
+ current_stack_allocations.get());
+ t->Announce();
+
+ PrintTagsAroundAddr(tag_ptr);
- ReportErrorSummary("tag-mismatch", stack);
+ ReportErrorSummary(bug_type, stack);
}
} // namespace __hwasan
diff --git a/lib/hwasan/hwasan_report.h b/lib/hwasan/hwasan_report.h
index bb33f1a87308..10fb20cc5be1 100644
--- a/lib/hwasan/hwasan_report.h
+++ b/lib/hwasan/hwasan_report.h
@@ -21,12 +21,12 @@
namespace __hwasan {
-void ReportInvalidAccess(StackTrace *stack, u32 origin);
void ReportStats();
-void ReportInvalidAccessInsideAddressRange(const char *what, const void *start,
- uptr size, uptr offset);
void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
- bool is_store);
+ bool is_store, bool fatal);
+void ReportInvalidFree(StackTrace *stack, uptr addr);
+void ReportTailOverwritten(StackTrace *stack, uptr addr, uptr orig_size,
+ uptr tail_size, const u8 *expected);
void ReportAtExitStatistics();
diff --git a/lib/hwasan/hwasan_thread.cc b/lib/hwasan/hwasan_thread.cc
index b50c0fc76be4..631c2813eb06 100644
--- a/lib/hwasan/hwasan_thread.cc
+++ b/lib/hwasan/hwasan_thread.cc
@@ -5,8 +5,11 @@
#include "hwasan_poisoning.h"
#include "hwasan_interface_internal.h"
+#include "sanitizer_common/sanitizer_file.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_tls_get_addr.h"
+
namespace __hwasan {
static u32 RandomSeed() {
@@ -22,69 +25,70 @@ static u32 RandomSeed() {
return seed;
}
-HwasanThread *HwasanThread::Create(thread_callback_t start_routine,
- void *arg) {
- uptr PageSize = GetPageSizeCached();
- uptr size = RoundUpTo(sizeof(HwasanThread), PageSize);
- HwasanThread *thread = (HwasanThread*)MmapOrDie(size, __func__);
- thread->start_routine_ = start_routine;
- thread->arg_ = arg;
- thread->destructor_iterations_ = GetPthreadDestructorIterations();
- thread->random_state_ = flags()->random_tags ? RandomSeed() : 0;
-
- return thread;
-}
-
-void HwasanThread::SetThreadStackAndTls() {
- uptr tls_size = 0;
- uptr stack_size = 0;
- GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_size,
- &tls_begin_, &tls_size);
+void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size) {
+ static u64 unique_id;
+ unique_id_ = unique_id++;
+ random_state_ = flags()->random_tags ? RandomSeed() : unique_id_;
+ if (auto sz = flags()->heap_history_size)
+ heap_allocations_ = HeapAllocationsRingBuffer::New(sz);
+
+ HwasanTSDThreadInit(); // Only needed with interceptors.
+ uptr *ThreadLong = GetCurrentThreadLongPtr();
+ // The following implicitly sets (this) as the current thread.
+ stack_allocations_ = new (ThreadLong)
+ StackAllocationsRingBuffer((void *)stack_buffer_start, stack_buffer_size);
+ // Check that it worked.
+ CHECK_EQ(GetCurrentThread(), this);
+
+ // ScopedTaggingDisable needs GetCurrentThread to be set up.
+ ScopedTaggingDisabler disabler;
+
+ 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;
- int local;
- CHECK(AddrIsInStack((uptr)&local));
-}
-
-void HwasanThread::Init() {
- SetThreadStackAndTls();
- CHECK(MEM_IS_APP(stack_bottom_));
- CHECK(MEM_IS_APP(stack_top_ - 1));
-}
+ if (stack_bottom_) {
+ int local;
+ CHECK(AddrIsInStack((uptr)&local));
+ CHECK(MemIsApp(stack_bottom_));
+ CHECK(MemIsApp(stack_top_ - 1));
+ }
-void HwasanThread::TSDDtor(void *tsd) {
- HwasanThread *t = (HwasanThread*)tsd;
- t->Destroy();
+ if (flags()->verbose_threads) {
+ if (IsMainThread()) {
+ Printf("sizeof(Thread): %zd sizeof(HeapRB): %zd sizeof(StackRB): %zd\n",
+ sizeof(Thread), heap_allocations_->SizeInBytes(),
+ stack_allocations_->size() * sizeof(uptr));
+ }
+ Print("Creating : ");
+ }
}
-void HwasanThread::ClearShadowForThreadStackAndTLS() {
- TagMemory(stack_bottom_, stack_top_ - stack_bottom_, 0);
+void Thread::ClearShadowForThreadStackAndTLS() {
+ if (stack_top_ != stack_bottom_)
+ TagMemory(stack_bottom_, stack_top_ - stack_bottom_, 0);
if (tls_begin_ != tls_end_)
TagMemory(tls_begin_, tls_end_ - tls_begin_, 0);
}
-void HwasanThread::Destroy() {
- malloc_storage().CommitBack();
+void Thread::Destroy() {
+ if (flags()->verbose_threads)
+ Print("Destroying: ");
+ AllocatorSwallowThreadLocalCache(allocator_cache());
ClearShadowForThreadStackAndTLS();
- uptr size = RoundUpTo(sizeof(HwasanThread), GetPageSizeCached());
- UnmapOrDie(this, size);
+ if (heap_allocations_)
+ heap_allocations_->Delete();
DTLS_Destroy();
}
-thread_return_t HwasanThread::ThreadStart() {
- Init();
-
- if (!start_routine_) {
- // start_routine_ == 0 if we're on the main thread or on one of the
- // OS X libdispatch worker threads. But nobody is supposed to call
- // ThreadStart() for the worker threads.
- return 0;
- }
-
- thread_return_t res = start_routine_(arg_);
-
- return res;
+void Thread::Print(const char *Prefix) {
+ Printf("%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p)\n", Prefix,
+ unique_id_, this, stack_bottom(), stack_top(),
+ stack_top() - stack_bottom(),
+ tls_begin(), tls_end());
}
static u32 xorshift(u32 state) {
@@ -95,7 +99,8 @@ static u32 xorshift(u32 state) {
}
// Generate a (pseudo-)random non-zero tag.
-tag_t HwasanThread::GenerateRandomTag() {
+tag_t Thread::GenerateRandomTag() {
+ if (tagging_disabled_) return 0;
tag_t tag;
do {
if (flags()->random_tags) {
diff --git a/lib/hwasan/hwasan_thread.h b/lib/hwasan/hwasan_thread.h
index 1e482adeac84..4830473f4aab 100644
--- a/lib/hwasan/hwasan_thread.h
+++ b/lib/hwasan/hwasan_thread.h
@@ -1,4 +1,4 @@
-//===-- hwasan_thread.h -------------------------------------------*- C++ -*-===//
+//===-- hwasan_thread.h -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -16,23 +16,23 @@
#include "hwasan_allocator.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_ring_buffer.h"
namespace __hwasan {
-class HwasanThread {
+typedef __sanitizer::CompactRingBuffer<uptr> StackAllocationsRingBuffer;
+
+class Thread {
public:
- static HwasanThread *Create(thread_callback_t start_routine, void *arg);
- static void TSDDtor(void *tsd);
+ void Init(uptr stack_buffer_start, uptr stack_buffer_size); // Must be called from the thread itself.
void Destroy();
- void Init(); // Should be called from the thread itself.
- thread_return_t ThreadStart();
-
uptr stack_top() { return stack_top_; }
uptr stack_bottom() { return stack_bottom_; }
+ uptr stack_size() { return stack_top() - stack_bottom(); }
uptr tls_begin() { return tls_begin_; }
uptr tls_end() { return tls_end_; }
- bool IsMainThread() { return start_routine_ == nullptr; }
+ bool IsMainThread() { return unique_id_ == 0; }
bool AddrIsInStack(uptr addr) {
return addr >= stack_bottom_ && addr < stack_top_;
@@ -50,19 +50,28 @@ class HwasanThread {
void EnterInterceptorScope() { in_interceptor_scope_++; }
void LeaveInterceptorScope() { in_interceptor_scope_--; }
- HwasanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
+ AllocatorCache *allocator_cache() { return &allocator_cache_; }
+ HeapAllocationsRingBuffer *heap_allocations() { return heap_allocations_; }
+ StackAllocationsRingBuffer *stack_allocations() { return stack_allocations_; }
tag_t GenerateRandomTag();
- int destructor_iterations_;
+ void DisableTagging() { tagging_disabled_++; }
+ void EnableTagging() { tagging_disabled_--; }
+ bool TaggingIsDisabled() const { return tagging_disabled_; }
+
+ u64 unique_id() const { return unique_id_; }
+ void Announce() {
+ if (announced_) return;
+ announced_ = true;
+ Print("Thread: ");
+ }
private:
- // NOTE: There is no HwasanThread constructor. It is allocated
+ // NOTE: There is no Thread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state.
- void SetThreadStackAndTls();
void ClearShadowForThreadStackAndTLS();
- thread_callback_t start_routine_;
- void *arg_;
+ void Print(const char *prefix);
uptr stack_top_;
uptr stack_bottom_;
uptr tls_begin_;
@@ -75,11 +84,30 @@ class HwasanThread {
u32 random_state_;
u32 random_buffer_;
- HwasanThreadLocalMallocStorage malloc_storage_;
+ AllocatorCache allocator_cache_;
+ HeapAllocationsRingBuffer *heap_allocations_;
+ StackAllocationsRingBuffer *stack_allocations_;
+
+ static void InsertIntoThreadList(Thread *t);
+ static void RemoveFromThreadList(Thread *t);
+ Thread *next_; // All live threads form a linked list.
+
+ u64 unique_id_; // counting from zero.
+
+ u32 tagging_disabled_; // if non-zero, malloc uses zero tag in this thread.
+
+ bool announced_;
+
+ friend struct ThreadListHead;
};
-HwasanThread *GetCurrentThread();
-void SetCurrentThread(HwasanThread *t);
+Thread *GetCurrentThread();
+uptr *GetCurrentThreadLongPtr();
+
+struct ScopedTaggingDisabler {
+ ScopedTaggingDisabler() { GetCurrentThread()->DisableTagging(); }
+ ~ScopedTaggingDisabler() { GetCurrentThread()->EnableTagging(); }
+};
} // namespace __hwasan
diff --git a/lib/hwasan/hwasan_thread_list.cc b/lib/hwasan/hwasan_thread_list.cc
new file mode 100644
index 000000000000..a31eee84ed93
--- /dev/null
+++ b/lib/hwasan/hwasan_thread_list.cc
@@ -0,0 +1,15 @@
+#include "hwasan_thread_list.h"
+
+namespace __hwasan {
+static ALIGNED(16) char thread_list_placeholder[sizeof(HwasanThreadList)];
+static HwasanThreadList *hwasan_thread_list;
+
+HwasanThreadList &hwasanThreadList() { return *hwasan_thread_list; }
+
+void InitThreadList(uptr storage, uptr size) {
+ CHECK(hwasan_thread_list == nullptr);
+ hwasan_thread_list =
+ new (thread_list_placeholder) HwasanThreadList(storage, size);
+}
+
+} // namespace
diff --git a/lib/hwasan/hwasan_thread_list.h b/lib/hwasan/hwasan_thread_list.h
new file mode 100644
index 000000000000..53747b51fd65
--- /dev/null
+++ b/lib/hwasan/hwasan_thread_list.h
@@ -0,0 +1,200 @@
+//===-- hwasan_thread_list.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of HWAddressSanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+// HwasanThreadList is a registry for live threads, as well as an allocator for
+// HwasanThread objects and their stack history ring buffers. There are
+// constraints on memory layout of the shadow region and CompactRingBuffer that
+// are part of the ABI contract between compiler-rt and llvm.
+//
+// * 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
+// 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
+// ring buffer,
+// A_next = (A + sizeof(uptr)) & ~((1 << (N + 13)) - 1)
+// is the address of the next element of that ring buffer (with wrap-around).
+// And, with K = kShadowBaseAlignment,
+// S = (A | ((1 << K) - 1)) + 1
+// (align up to kShadowBaseAlignment) is the start of the shadow region.
+//
+// These calculations are used in compiler instrumentation to update the ring
+// buffer and obtain the base address of shadow using only two inputs: address
+// of the current element of the ring buffer, and N (i.e. size of the ring
+// buffer). Since the value of N is very limited, we pack both inputs into a
+// single thread-local word as
+// (1 << (N + 56)) | A
+// See the implementation of class CompactRingBuffer, which is what is stored in
+// said thread-local word.
+//
+// Note the unusual way of aligning up the address of the shadow:
+// (A | ((1 << K) - 1)) + 1
+// It is only correct if A is not already equal to the shadow base address, but
+// it saves 2 instructions on AArch64.
+
+#include "hwasan.h"
+#include "hwasan_allocator.h"
+#include "hwasan_flags.h"
+#include "hwasan_thread.h"
+
+#include "sanitizer_common/sanitizer_placement_new.h"
+
+namespace __hwasan {
+
+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) {
+ uptr size = 4096 * (1ULL << shift);
+ if (size >= desired_bytes)
+ return size;
+ }
+ Printf("stack history size too large: %d\n", flags()->stack_history_size);
+ CHECK(0);
+ return 0;
+}
+
+struct ThreadListHead {
+ Thread *list_;
+
+ ThreadListHead() : list_(nullptr) {}
+
+ void Push(Thread *t) {
+ t->next_ = list_;
+ list_ = t;
+ }
+
+ Thread *Pop() {
+ Thread *t = list_;
+ if (t)
+ list_ = t->next_;
+ return t;
+ }
+
+ void Remove(Thread *t) {
+ Thread **cur = &list_;
+ while (*cur != t) cur = &(*cur)->next_;
+ CHECK(*cur && "thread not found");
+ *cur = (*cur)->next_;
+ }
+
+ template <class CB>
+ void ForEach(CB cb) {
+ Thread *t = list_;
+ while (t) {
+ cb(t);
+ t = t->next_;
+ }
+ }
+};
+
+struct ThreadStats {
+ uptr n_live_threads;
+ uptr total_stack_size;
+};
+
+class HwasanThreadList {
+ public:
+ HwasanThreadList(uptr storage, uptr size)
+ : free_space_(storage),
+ free_space_end_(storage + size),
+ ring_buffer_size_(RingBufferSize()) {}
+
+ Thread *CreateCurrentThread() {
+ Thread *t;
+ {
+ SpinMutexLock l(&list_mutex_);
+ t = free_list_.Pop();
+ if (t)
+ internal_memset((void *)t, 0, sizeof(Thread) + ring_buffer_size_);
+ else
+ t = AllocThread();
+ live_list_.Push(t);
+ }
+ t->Init((uptr)(t + 1), ring_buffer_size_);
+ AddThreadStats(t);
+ return t;
+ }
+
+ void ReleaseThread(Thread *t) {
+ // FIXME: madvise away the ring buffer?
+ RemoveThreadStats(t);
+ t->Destroy();
+ SpinMutexLock l(&list_mutex_);
+ live_list_.Remove(t);
+ free_list_.Push(t);
+ }
+
+ Thread *GetThreadByBufferAddress(uptr p) {
+ uptr align = ring_buffer_size_ * 2;
+ return (Thread *)(RoundDownTo(p, align) - sizeof(Thread));
+ }
+
+ uptr MemoryUsedPerThread() {
+ uptr res = sizeof(Thread) + ring_buffer_size_;
+ if (auto sz = flags()->heap_history_size)
+ res += HeapAllocationsRingBuffer::SizeInBytes(sz);
+ return res;
+ }
+
+ template <class CB>
+ void VisitAllLiveThreads(CB cb) {
+ SpinMutexLock l(&list_mutex_);
+ live_list_.ForEach(cb);
+ }
+
+ void AddThreadStats(Thread *t) {
+ SpinMutexLock l(&stats_mutex_);
+ stats_.n_live_threads++;
+ stats_.total_stack_size += t->stack_size();
+ }
+
+ void RemoveThreadStats(Thread *t) {
+ SpinMutexLock l(&stats_mutex_);
+ stats_.n_live_threads--;
+ stats_.total_stack_size -= t->stack_size();
+ }
+
+ ThreadStats GetThreadStats() {
+ SpinMutexLock l(&stats_mutex_);
+ return stats_;
+ }
+
+ private:
+ Thread *AllocThread() {
+ uptr align = ring_buffer_size_ * 2;
+ uptr ring_buffer_start = RoundUpTo(free_space_ + sizeof(Thread), align);
+ free_space_ = ring_buffer_start + ring_buffer_size_;
+ CHECK(free_space_ <= free_space_end_ && "out of thread memory");
+ return (Thread *)(ring_buffer_start - sizeof(Thread));
+ }
+
+ uptr free_space_;
+ uptr free_space_end_;
+ uptr ring_buffer_size_;
+
+ ThreadListHead free_list_;
+ ThreadListHead live_list_;
+ SpinMutex list_mutex_;
+
+ ThreadStats stats_;
+ SpinMutex stats_mutex_;
+};
+
+void InitThreadList(uptr storage, uptr size);
+HwasanThreadList &hwasanThreadList();
+
+} // namespace
diff --git a/lib/interception/interception.h b/lib/interception/interception.h
index ddd6ec20979b..87b2365fd767 100644
--- a/lib/interception/interception.h
+++ b/lib/interception/interception.h
@@ -29,6 +29,7 @@ typedef __sanitizer::uptr SIZE_T;
typedef __sanitizer::sptr SSIZE_T;
typedef __sanitizer::sptr PTRDIFF_T;
typedef __sanitizer::s64 INTMAX_T;
+typedef __sanitizer::u64 UINTMAX_T;
typedef __sanitizer::OFF_T OFF_T;
typedef __sanitizer::OFF64_T OFF64_T;
@@ -169,7 +170,7 @@ const interpose_substitution substitution_##func_name[] \
#elif !SANITIZER_MAC
# define PTR_TO_REAL(x) real_##x
# define REAL(x) __interception::PTR_TO_REAL(x)
-# define FUNC_TYPE(x) x##_f
+# define FUNC_TYPE(x) x##_type
# define DECLARE_REAL(ret_type, func, ...) \
typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
diff --git a/lib/interception/interception_linux.h b/lib/interception/interception_linux.h
index 942c25609ccb..765a186e5823 100644
--- a/lib/interception/interception_linux.h
+++ b/lib/interception/interception_linux.h
@@ -38,7 +38,7 @@ void *GetFuncAddrVer(const char *func_name, const char *ver);
// Android, Solaris and OpenBSD do not have dlvsym
#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD
#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
- (::__interception::real_##func = (func##_f)( \
+ (::__interception::real_##func = (func##_type)( \
unsigned long)::__interception::GetFuncAddrVer(#func, symver))
#else
#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc
index bd4ad7274dde..cd13827e5857 100644
--- a/lib/interception/interception_win.cc
+++ b/lib/interception/interception_win.cc
@@ -223,8 +223,8 @@ static bool IsMemoryPadding(uptr address, uptr size) {
return true;
}
-static const u8 kHintNop9Bytes[] = {
- 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
+static const u8 kHintNop8Bytes[] = {
+ 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
};
template<class T>
@@ -239,8 +239,8 @@ static bool FunctionHasPrefix(uptr address, const T &pattern) {
static bool FunctionHasPadding(uptr address, uptr size) {
if (IsMemoryPadding(address - size, size))
return true;
- if (size <= sizeof(kHintNop9Bytes) &&
- FunctionHasPrefix(address, kHintNop9Bytes))
+ if (size <= sizeof(kHintNop8Bytes) &&
+ FunctionHasPrefix(address, kHintNop8Bytes))
return true;
return false;
}
diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc
index c58c3548002f..1b338bd5973e 100644
--- a/lib/lsan/lsan_allocator.cc
+++ b/lib/lsan/lsan_allocator.cc
@@ -34,9 +34,6 @@ static const uptr kMaxAllowedMallocSize = 4UL << 30;
#else
static const uptr kMaxAllowedMallocSize = 8UL << 30;
#endif
-typedef LargeMmapAllocator<> SecondaryAllocator;
-typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
- SecondaryAllocator> Allocator;
static Allocator allocator;
diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h
index 7c70bb6d9766..4c4e02fc0902 100644
--- a/lib/lsan/lsan_allocator.h
+++ b/lib/lsan/lsan_allocator.h
@@ -54,19 +54,25 @@ struct ChunkMetadata {
defined(__arm__)
static const uptr kRegionSizeLog = 20;
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
-typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+template <typename AddressSpaceView>
+using ByteMapASVT =
+ TwoLevelByteMap<(kNumRegions >> 12), 1 << 12, AddressSpaceView>;
+template <typename AddressSpaceViewTy>
struct AP32 {
static const uptr kSpaceBeg = 0;
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
static const uptr kMetadataSize = sizeof(ChunkMetadata);
typedef __sanitizer::CompactSizeClassMap SizeClassMap;
static const uptr kRegionSizeLog = __lsan::kRegionSizeLog;
- typedef __lsan::ByteMap ByteMap;
+ using AddressSpaceView = AddressSpaceViewTy;
+ using ByteMap = __lsan::ByteMapASVT<AddressSpaceView>;
typedef NoOpMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
};
-typedef SizeClassAllocator32<AP32> PrimaryAllocator;
+template <typename AddressSpaceView>
+using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
+using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
#elif defined(__x86_64__) || defined(__powerpc64__)
# if defined(__powerpc64__)
const uptr kAllocatorSpace = 0xa0000000000ULL;
@@ -75,6 +81,7 @@ const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
const uptr kAllocatorSpace = 0x600000000000ULL;
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
# endif
+template <typename AddressSpaceViewTy>
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
static const uptr kSpaceBeg = kAllocatorSpace;
static const uptr kSpaceSize = kAllocatorSize;
@@ -82,11 +89,30 @@ struct AP64 { // Allocator64 parameters. Deliberately using a short name.
typedef DefaultSizeClassMap SizeClassMap;
typedef NoOpMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
+ using AddressSpaceView = AddressSpaceViewTy;
};
-typedef SizeClassAllocator64<AP64> PrimaryAllocator;
+template <typename AddressSpaceView>
+using PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
+using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
#endif
-typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+
+template <typename AddressSpaceView>
+using AllocatorCacheASVT =
+ SizeClassAllocatorLocalCache<PrimaryAllocatorASVT<AddressSpaceView>>;
+using AllocatorCache = AllocatorCacheASVT<LocalAddressSpaceView>;
+
+template <typename AddressSpaceView>
+using SecondaryAllocatorASVT =
+ LargeMmapAllocator<NoOpMapUnmapCallback, DefaultLargeMmapAllocatorPtrArray,
+ AddressSpaceView>;
+
+template <typename AddressSpaceView>
+using AllocatorASVT =
+ CombinedAllocator<PrimaryAllocatorASVT<AddressSpaceView>,
+ AllocatorCacheASVT<AddressSpaceView>,
+ SecondaryAllocatorASVT<AddressSpaceView>>;
+using Allocator = AllocatorASVT<LocalAddressSpaceView>;
AllocatorCache *GetAllocatorCache();
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
index 012a673c3b25..eaa5cadc8ffb 100644
--- a/lib/lsan/lsan_common.cc
+++ b/lib/lsan/lsan_common.cc
@@ -100,8 +100,6 @@ static SuppressionContext *GetSuppressionContext() {
static InternalMmapVector<RootRegion> *root_regions;
-static uptr initialized_for_pid;
-
InternalMmapVector<RootRegion> const *GetRootRegions() { return root_regions; }
void InitializeRootRegions() {
@@ -115,7 +113,6 @@ const char *MaybeCallLsanDefaultOptions() {
}
void InitCommonLsan() {
- initialized_for_pid = internal_getpid();
InitializeRootRegions();
if (common_flags()->detect_leaks) {
// Initialization which can fail or print warnings should only be done if
@@ -571,12 +568,6 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
static bool CheckForLeaks() {
if (&__lsan_is_turned_off && __lsan_is_turned_off())
return false;
- if (initialized_for_pid != internal_getpid()) {
- // If process was forked and it had threads we fail to detect references
- // from other threads.
- Report("WARNING: LeakSanitizer is disabled in forked process.\n");
- return false;
- }
EnsureMainThreadIDIsCorrect();
CheckForLeaksParam param;
param.success = false;
diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc
index 2508c1dbd873..a355cea96c43 100644
--- a/lib/lsan/lsan_common_mac.cc
+++ b/lib/lsan/lsan_common_mac.cc
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
+#include "sanitizer_common/sanitizer_libc.h"
#include "lsan_common.h"
#if CAN_SANITIZE_LEAKS && SANITIZER_MAC
@@ -116,7 +117,8 @@ static const char *kSkippedSecNames[] = {
// Scans global variables for heap pointers.
void ProcessGlobalRegions(Frontier *frontier) {
- for (auto name : kSkippedSecNames) CHECK(ARRAY_SIZE(name) < kMaxSegName);
+ for (auto name : kSkippedSecNames)
+ CHECK(internal_strnlen(name, kMaxSegName + 1) <= kMaxSegName);
MemoryMappingLayout memory_mapping(false);
InternalMmapVector<LoadedModule> modules;
@@ -142,12 +144,6 @@ void ProcessGlobalRegions(Frontier *frontier) {
}
void ProcessPlatformSpecificAllocations(Frontier *frontier) {
- mach_port_name_t port;
- if (task_for_pid(mach_task_self(), internal_getpid(), &port)
- != KERN_SUCCESS) {
- return;
- }
-
unsigned depth = 1;
vm_size_t size = 0;
vm_address_t address = 0;
@@ -158,7 +154,7 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) {
while (err == KERN_SUCCESS) {
struct vm_region_submap_info_64 info;
- err = vm_region_recurse_64(port, &address, &size, &depth,
+ err = vm_region_recurse_64(mach_task_self(), &address, &size, &depth,
(vm_region_info_t)&info, &count);
uptr end_address = address + size;
diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc
index fde52e496164..a9bd2ba42319 100644
--- a/lib/lsan/lsan_interceptors.cc
+++ b/lib/lsan/lsan_interceptors.cc
@@ -153,7 +153,7 @@ INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
#define LSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
INTERCEPTOR(int, mallopt, int cmd, int value) {
- return -1;
+ return 0;
}
#define LSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
#else
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index 06bcbdf88691..ba2d5d593303 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -59,6 +59,10 @@ SANITIZER_INTERFACE_ATTRIBUTE
ALIGNED(16) THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)];
SANITIZER_INTERFACE_ATTRIBUTE
+ALIGNED(16)
+THREADLOCAL u32 __msan_va_arg_origin_tls[kMsanParamTlsSize / sizeof(u32)];
+
+SANITIZER_INTERFACE_ATTRIBUTE
THREADLOCAL u64 __msan_va_arg_overflow_size_tls;
SANITIZER_INTERFACE_ATTRIBUTE
@@ -277,6 +281,8 @@ void ScopedThreadLocalStateBackup::Restore() {
internal_memset(__msan_param_tls, 0, sizeof(__msan_param_tls));
internal_memset(__msan_retval_tls, 0, sizeof(__msan_retval_tls));
internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls));
+ internal_memset(__msan_va_arg_origin_tls, 0,
+ sizeof(__msan_va_arg_origin_tls));
if (__msan_get_track_origins()) {
internal_memset(&__msan_retval_origin_tls, 0,
diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc
index 36f0497a9d83..053ab0280397 100644
--- a/lib/msan/msan_allocator.cc
+++ b/lib/msan/msan_allocator.cc
@@ -57,7 +57,8 @@ struct MsanMapUnmapCallback {
static const uptr kMetadataSize = sizeof(Metadata);
typedef __sanitizer::CompactSizeClassMap SizeClassMap;
static const uptr kRegionSizeLog = __msan::kRegionSizeLog;
- typedef __msan::ByteMap ByteMap;
+ using AddressSpaceView = LocalAddressSpaceView;
+ using ByteMap = __msan::ByteMap;
typedef MsanMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
};
@@ -78,6 +79,7 @@ struct MsanMapUnmapCallback {
typedef DefaultSizeClassMap SizeClassMap;
typedef MsanMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
+ using AddressSpaceView = LocalAddressSpaceView;
};
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
@@ -92,6 +94,7 @@ struct MsanMapUnmapCallback {
typedef DefaultSizeClassMap SizeClassMap;
typedef MsanMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
+ using AddressSpaceView = LocalAddressSpaceView;
};
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
@@ -107,7 +110,8 @@ struct MsanMapUnmapCallback {
static const uptr kMetadataSize = sizeof(Metadata);
typedef __sanitizer::CompactSizeClassMap SizeClassMap;
static const uptr kRegionSizeLog = __msan::kRegionSizeLog;
- typedef __msan::ByteMap ByteMap;
+ using AddressSpaceView = LocalAddressSpaceView;
+ using ByteMap = __msan::ByteMap;
typedef MsanMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
};
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index b3429bcf06b5..497f943a8a0e 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -34,11 +34,13 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_tls_get_addr.h"
+#include "sanitizer_common/sanitizer_vector.h"
#if SANITIZER_NETBSD
#define fstat __fstat50
#define gettimeofday __gettimeofday50
#define getrusage __getrusage50
+#define tzset __tzset50
#endif
#include <stdarg.h>
@@ -249,11 +251,11 @@ INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
// temporary! The following is equivalent on all supported platforms but
// aarch64 (which uses a different register for sret value). We have a test
// to confirm that.
-INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) {
+INTERCEPTOR(void, mallinfo, __sanitizer_struct_mallinfo *sret) {
#ifdef __aarch64__
uptr r8;
asm volatile("mov %0,x8" : "=r" (r8));
- sret = reinterpret_cast<__sanitizer_mallinfo*>(r8);
+ sret = reinterpret_cast<__sanitizer_struct_mallinfo*>(r8);
#endif
REAL(memset)(sret, 0, sizeof(*sret));
__msan_unpoison(sret, sizeof(*sret));
@@ -265,7 +267,7 @@ INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) {
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
INTERCEPTOR(int, mallopt, int cmd, int value) {
- return -1;
+ return 0;
}
#define MSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
#else
@@ -1071,6 +1073,7 @@ extern char *tzname[2];
INTERCEPTOR(void, tzset, int fake) {
ENSURE_MSAN_INITED();
+ InterceptorScope interceptor_scope;
REAL(tzset)(fake);
if (tzname[0])
__msan_unpoison(tzname[0], REAL(strlen)(tzname[0]) + 1);
@@ -1084,23 +1087,80 @@ struct MSanAtExitRecord {
void *arg;
};
-void MSanAtExitWrapper(void *arg) {
+struct InterceptorContext {
+ BlockingMutex atexit_mu;
+ Vector<struct MSanAtExitRecord *> AtExitStack;
+
+ InterceptorContext()
+ : AtExitStack() {
+ }
+};
+
+static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)];
+InterceptorContext *interceptor_ctx() {
+ return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]);
+}
+
+void MSanAtExitWrapper() {
+ MSanAtExitRecord *r;
+ {
+ BlockingMutexLock l(&interceptor_ctx()->atexit_mu);
+
+ uptr element = interceptor_ctx()->AtExitStack.Size() - 1;
+ r = interceptor_ctx()->AtExitStack[element];
+ interceptor_ctx()->AtExitStack.PopBack();
+ }
+
+ UnpoisonParam(1);
+ ((void(*)())r->func)();
+ InternalFree(r);
+}
+
+void MSanCxaAtExitWrapper(void *arg) {
UnpoisonParam(1);
MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
r->func(r->arg);
InternalFree(r);
}
+static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso);
+
// Unpoison argument shadow for C++ module destructors.
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
void *dso_handle) {
if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle);
+ return setup_at_exit_wrapper((void(*)())func, arg, dso_handle);
+}
+
+// Unpoison argument shadow for C++ module destructors.
+INTERCEPTOR(int, atexit, void (*func)()) {
+ // Avoid calling real atexit as it is unrechable on at least on Linux.
+ if (msan_init_is_running)
+ return REAL(__cxa_atexit)((void (*)(void *a))func, 0, 0);
+ return setup_at_exit_wrapper((void(*)())func, 0, 0);
+}
+
+static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso) {
ENSURE_MSAN_INITED();
MSanAtExitRecord *r =
(MSanAtExitRecord *)InternalAlloc(sizeof(MSanAtExitRecord));
- r->func = func;
+ r->func = (void(*)(void *a))f;
r->arg = arg;
- return REAL(__cxa_atexit)(MSanAtExitWrapper, r, dso_handle);
+ int res;
+ if (!dso) {
+ // NetBSD does not preserve the 2nd argument if dso is equal to 0
+ // Store ctx in a local stack-like structure
+
+ BlockingMutexLock l(&interceptor_ctx()->atexit_mu);
+
+ res = REAL(__cxa_atexit)((void (*)(void *a))MSanAtExitWrapper, 0, 0);
+ if (!res) {
+ interceptor_ctx()->AtExitStack.PushBack(r);
+ }
+ } else {
+ res = REAL(__cxa_atexit)(MSanCxaAtExitWrapper, r, dso);
+ }
+ return res;
}
static void BeforeFork() {
@@ -1520,6 +1580,9 @@ namespace __msan {
void InitializeInterceptors() {
static int inited = 0;
CHECK_EQ(inited, 0);
+
+ new(interceptor_ctx()) InterceptorContext();
+
InitializeCommonInterceptors();
InitializeSignalInterceptors();
@@ -1629,6 +1692,7 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(pthread_join);
INTERCEPT_FUNCTION(tzset);
+ INTERCEPT_FUNCTION(atexit);
INTERCEPT_FUNCTION(__cxa_atexit);
INTERCEPT_FUNCTION(shmat);
INTERCEPT_FUNCTION(fork);
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc
index 385a650c4afc..0b0208884d2f 100644
--- a/lib/msan/msan_linux.cc
+++ b/lib/msan/msan_linux.cc
@@ -175,6 +175,51 @@ void InstallAtExitHandler() {
// ---------------------- TSD ---------------- {{{1
+#if SANITIZER_NETBSD || SANITIZER_FREEBSD
+// Thread Static Data cannot be used in early init on NetBSD and FreeBSD.
+// Reuse the MSan TSD API for compatibility with existing code
+// with an alternative implementation.
+
+static void (*tsd_destructor)(void *tsd) = nullptr;
+
+struct tsd_key {
+ tsd_key() : key(nullptr) {}
+ ~tsd_key() {
+ CHECK(tsd_destructor);
+ if (key)
+ (*tsd_destructor)(key);
+ }
+ MsanThread *key;
+};
+
+static thread_local struct tsd_key key;
+
+void MsanTSDInit(void (*destructor)(void *tsd)) {
+ CHECK(!tsd_destructor);
+ tsd_destructor = destructor;
+}
+
+MsanThread *GetCurrentThread() {
+ CHECK(tsd_destructor);
+ return key.key;
+}
+
+void SetCurrentThread(MsanThread *tsd) {
+ CHECK(tsd_destructor);
+ CHECK(tsd);
+ CHECK(!key.key);
+ key.key = tsd;
+}
+
+void MsanTSDDtor(void *tsd) {
+ CHECK(tsd_destructor);
+ CHECK_EQ(key.key, tsd);
+ key.key = nullptr;
+ // Make sure that signal handler can not see a stale current thread pointer.
+ atomic_signal_fence(memory_order_seq_cst);
+ MsanThread::TSDDtor(tsd);
+}
+#else
static pthread_key_t tsd_key;
static bool tsd_key_inited = false;
@@ -211,6 +256,7 @@ void MsanTSDDtor(void *tsd) {
atomic_signal_fence(memory_order_seq_cst);
MsanThread::TSDDtor(tsd);
}
+#endif
} // namespace __msan
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index 29260f16e704..19f46abdc574 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -1934,12 +1934,14 @@ TEST(MemorySanitizer, remquof) {
EXPECT_NOT_POISONED(quo);
}
+#if !defined(__NetBSD__)
TEST(MemorySanitizer, remquol) {
int quo;
long double res = remquof(29.0, 3.0, &quo);
ASSERT_NE(0.0, res);
EXPECT_NOT_POISONED(quo);
}
+#endif
TEST(MemorySanitizer, lgamma) {
double res = lgamma(1.1);
@@ -1953,11 +1955,13 @@ TEST(MemorySanitizer, lgammaf) {
EXPECT_NOT_POISONED(signgam);
}
+#if !defined(__NetBSD__)
TEST(MemorySanitizer, lgammal) {
long double res = lgammal(1.1);
ASSERT_NE(0.0, res);
EXPECT_NOT_POISONED(signgam);
}
+#endif
TEST(MemorySanitizer, lgamma_r) {
int sgn;
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index cbca365510b5..0665a680cf01 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -29,6 +29,8 @@
#include <string.h>
#if defined(_WIN32)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
#include "WindowsMMap.h"
#else
#include <sys/mman.h>
@@ -86,6 +88,9 @@ static uint64_t cur_buffer_size = 0;
static uint64_t cur_pos = 0;
static uint64_t file_size = 0;
static int new_file = 0;
+#if defined(_WIN32)
+static HANDLE mmap_handle = NULL;
+#endif
static int fd = -1;
typedef void (*fn_ptr)();
@@ -255,6 +260,28 @@ static int map_file() {
if (file_size == 0)
return -1;
+#if defined(_WIN32)
+ HANDLE mmap_fd;
+ if (fd == -1)
+ mmap_fd = INVALID_HANDLE_VALUE;
+ else
+ mmap_fd = (HANDLE)_get_osfhandle(fd);
+
+ mmap_handle = CreateFileMapping(mmap_fd, NULL, PAGE_READWRITE, DWORD_HI(file_size), DWORD_LO(file_size), NULL);
+ if (mmap_handle == NULL) {
+ fprintf(stderr, "profiling: %s: cannot create file mapping: %d\n", filename,
+ GetLastError());
+ return -1;
+ }
+
+ write_buffer = MapViewOfFile(mmap_handle, FILE_MAP_WRITE, 0, 0, file_size);
+ if (write_buffer == NULL) {
+ fprintf(stderr, "profiling: %s: cannot map: %d\n", filename,
+ GetLastError());
+ CloseHandle(mmap_handle);
+ return -1;
+ }
+#else
write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE,
MAP_FILE | MAP_SHARED, fd, 0);
if (write_buffer == (void *)-1) {
@@ -263,10 +290,30 @@ static int map_file() {
strerror(errnum));
return -1;
}
+#endif
+
return 0;
}
static void unmap_file() {
+#if defined(_WIN32)
+ if (!FlushViewOfFile(write_buffer, file_size)) {
+ fprintf(stderr, "profiling: %s: cannot flush mapped view: %d\n", filename,
+ GetLastError());
+ }
+
+ if (!UnmapViewOfFile(write_buffer)) {
+ fprintf(stderr, "profiling: %s: cannot unmap mapped view: %d\n", filename,
+ GetLastError());
+ }
+
+ if (!CloseHandle(mmap_handle)) {
+ fprintf(stderr, "profiling: %s: cannot close file mapping handle: %d\n", filename,
+ GetLastError());
+ }
+
+ mmap_handle = NULL;
+#else
if (msync(write_buffer, file_size, MS_SYNC) == -1) {
int errnum = errno;
fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename,
@@ -277,6 +324,8 @@ static void unmap_file() {
* is written and we don't care.
*/
(void)munmap(write_buffer, file_size);
+#endif
+
write_buffer = NULL;
file_size = 0;
}
diff --git a/lib/profile/InstrProfData.inc b/lib/profile/InstrProfData.inc
index eb4a792ce82d..454620ed997a 100644
--- a/lib/profile/InstrProfData.inc
+++ b/lib/profile/InstrProfData.inc
@@ -308,14 +308,14 @@ typedef struct ValueProfRecord {
#ifdef __cplusplus
/*!
- * \brief Return the number of value sites.
+ * Return the number of value sites.
*/
uint32_t getNumValueSites() const { return NumValueSites; }
/*!
- * \brief Read data from this record and save it to Record.
+ * Read data from this record and save it to Record.
*/
void deserializeTo(InstrProfRecord &Record,
- InstrProfRecord::ValueMapType *VMap);
+ InstrProfSymtab *SymTab);
/*
* In-place byte swap:
* Do byte swap for this instance. \c Old is the original order before
@@ -393,7 +393,7 @@ typedef struct ValueProfData {
* Read data from this data and save it to \c Record.
*/
void deserializeTo(InstrProfRecord &Record,
- InstrProfRecord::ValueMapType *VMap);
+ InstrProfSymtab *SymTab);
void operator delete(void *ptr) { ::operator delete(ptr); }
#endif
} ValueProfData;
@@ -458,7 +458,7 @@ getValueProfRecordHeaderSize(uint32_t NumValueSites);
#endif
/*!
- * \brief Return the \c ValueProfRecord header size including the
+ * Return the \c ValueProfRecord header size including the
* padding bytes.
*/
INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
@@ -471,7 +471,7 @@ uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) {
}
/*!
- * \brief Return the total size of the value profile record including the
+ * Return the total size of the value profile record including the
* header and the value data.
*/
INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
@@ -482,7 +482,7 @@ uint32_t getValueProfRecordSize(uint32_t NumValueSites,
}
/*!
- * \brief Return the pointer to the start of value data array.
+ * Return the pointer to the start of value data array.
*/
INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) {
@@ -491,7 +491,7 @@ InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) {
}
/*!
- * \brief Return the total number of value data for \c This record.
+ * Return the total number of value data for \c This record.
*/
INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) {
@@ -503,7 +503,7 @@ uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) {
}
/*!
- * \brief Use this method to advance to the next \c This \c ValueProfRecord.
+ * Use this method to advance to the next \c This \c ValueProfRecord.
*/
INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) {
@@ -514,7 +514,7 @@ ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) {
}
/*!
- * \brief Return the first \c ValueProfRecord instance.
+ * Return the first \c ValueProfRecord instance.
*/
INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) {
diff --git a/lib/profile/InstrProfilingPlatformLinux.c b/lib/profile/InstrProfilingPlatformLinux.c
index a517821a2fbd..3764df1d8079 100644
--- a/lib/profile/InstrProfilingPlatformLinux.c
+++ b/lib/profile/InstrProfilingPlatformLinux.c
@@ -8,7 +8,7 @@
\*===----------------------------------------------------------------------===*/
#if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
- (defined(__sun__) && defined(__svr4__))
+ (defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__)
#include <stdlib.h>
diff --git a/lib/profile/InstrProfilingPlatformOther.c b/lib/profile/InstrProfilingPlatformOther.c
index a339abc7f883..7c2f14cfce16 100644
--- a/lib/profile/InstrProfilingPlatformOther.c
+++ b/lib/profile/InstrProfilingPlatformOther.c
@@ -8,7 +8,7 @@
\*===----------------------------------------------------------------------===*/
#if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) && \
- !(defined(__sun__) && defined(__svr4__))
+ !(defined(__sun__) && defined(__svr4__)) && !defined(__NetBSD__)
#include <stdlib.h>
diff --git a/lib/profile/InstrProfilingValue.c b/lib/profile/InstrProfilingValue.c
index 674a48609878..c7b01a570649 100644
--- a/lib/profile/InstrProfilingValue.c
+++ b/lib/profile/InstrProfilingValue.c
@@ -105,8 +105,7 @@ static int allocateValueProfileCounters(__llvm_profile_data *Data) {
return 1;
}
-static ValueProfNode *allocateOneNode(__llvm_profile_data *Data, uint32_t Index,
- uint64_t Value) {
+static ValueProfNode *allocateOneNode(void) {
ValueProfNode *Node;
if (!hasStaticCounters)
@@ -205,7 +204,7 @@ instrumentTargetValueImpl(uint64_t TargetValue, void *Data,
return;
}
- CurVNode = allocateOneNode(PData, CounterIndex, TargetValue);
+ CurVNode = allocateOneNode();
if (!CurVNode)
return;
CurVNode->Value = TargetValue;
diff --git a/lib/profile/WindowsMMap.c b/lib/profile/WindowsMMap.c
index dc87a888ae7b..41cc67f41f1f 100644
--- a/lib/profile/WindowsMMap.c
+++ b/lib/profile/WindowsMMap.c
@@ -24,14 +24,6 @@
#include "InstrProfiling.h"
-#ifdef __USE_FILE_OFFSET64
-# define DWORD_HI(x) (x >> 32)
-# define DWORD_LO(x) ((x) & 0xffffffff)
-#else
-# define DWORD_HI(x) (0)
-# define DWORD_LO(x) (x)
-#endif
-
COMPILER_RT_VISIBILITY
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
{
diff --git a/lib/profile/WindowsMMap.h b/lib/profile/WindowsMMap.h
index 271619aea09a..51a130b31977 100644
--- a/lib/profile/WindowsMMap.h
+++ b/lib/profile/WindowsMMap.h
@@ -12,7 +12,7 @@
#if defined(_WIN32)
-#include <BaseTsd.h>
+#include <basetsd.h>
#include <io.h>
#include <sys/types.h>
@@ -45,6 +45,14 @@
#define LOCK_NB 4 /* don't block when locking */
#define LOCK_UN 8 /* unlock */
+#ifdef __USE_FILE_OFFSET64
+# define DWORD_HI(x) (x >> 32)
+# define DWORD_LO(x) ((x) & 0xffffffff)
+#else
+# define DWORD_HI(x) (0)
+# define DWORD_LO(x) (x)
+#endif
+
void *mmap(void *start, size_t length, int prot, int flags, int fd,
off_t offset);
diff --git a/lib/safestack/CMakeLists.txt b/lib/safestack/CMakeLists.txt
index 5a1bac2912b7..cc874a3fe8f1 100644
--- a/lib/safestack/CMakeLists.txt
+++ b/lib/safestack/CMakeLists.txt
@@ -6,29 +6,14 @@ include_directories(..)
set(SAFESTACK_CFLAGS ${SANITIZER_COMMON_CFLAGS})
-if(APPLE)
- # Build universal binary on APPLE.
+foreach(arch ${SAFESTACK_SUPPORTED_ARCH})
add_compiler_rt_runtime(clang_rt.safestack
STATIC
- OS osx
- ARCHS ${SAFESTACK_SUPPORTED_ARCH}
+ ARCHS ${arch}
SOURCES ${SAFESTACK_SOURCES}
- $<TARGET_OBJECTS:RTInterception.osx>
- $<TARGET_OBJECTS:RTSanitizerCommon.osx>
- $<TARGET_OBJECTS:RTSanitizerCommonNoLibc.osx>
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonNoLibc.${arch}>
CFLAGS ${SAFESTACK_CFLAGS}
PARENT_TARGET safestack)
-else()
- # Otherwise, build separate libraries for each target.
- foreach(arch ${SAFESTACK_SUPPORTED_ARCH})
- add_compiler_rt_runtime(clang_rt.safestack
- STATIC
- ARCHS ${arch}
- SOURCES ${SAFESTACK_SOURCES}
- $<TARGET_OBJECTS:RTInterception.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
- $<TARGET_OBJECTS:RTSanitizerCommonNoLibc.${arch}>
- CFLAGS ${SAFESTACK_CFLAGS}
- PARENT_TARGET safestack)
- endforeach()
-endif()
+endforeach()
diff --git a/lib/safestack/safestack.cc b/lib/safestack/safestack.cc
index 8af93624b991..e68208015fb9 100644
--- a/lib/safestack/safestack.cc
+++ b/lib/safestack/safestack.cc
@@ -14,11 +14,13 @@
//
//===----------------------------------------------------------------------===//
+#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
+#include <stdlib.h>
#include <sys/resource.h>
#include <sys/types.h>
#if !defined(__NetBSD__)
@@ -115,14 +117,6 @@ static inline void unsafe_stack_setup(void *start, size_t size, size_t guard) {
unsafe_stack_guard = guard;
}
-static void unsafe_stack_free() {
- if (unsafe_stack_start) {
- UnmapOrDie((char *)unsafe_stack_start - unsafe_stack_guard,
- unsafe_stack_size + unsafe_stack_guard);
- }
- unsafe_stack_start = nullptr;
-}
-
/// Thread data for the cleanup handler
static pthread_key_t thread_cleanup_key;
@@ -149,26 +143,73 @@ static void *thread_start(void *arg) {
tinfo->unsafe_stack_guard);
// Make sure out thread-specific destructor will be called
- // FIXME: we can do this only any other specific key is set by
- // intercepting the pthread_setspecific function itself
pthread_setspecific(thread_cleanup_key, (void *)1);
return start_routine(start_routine_arg);
}
-/// Thread-specific data destructor
+/// Linked list used to store exiting threads stack/thread information.
+struct thread_stack_ll {
+ struct thread_stack_ll *next;
+ void *stack_base;
+ size_t size;
+ pid_t pid;
+ tid_t tid;
+};
+
+/// Linked list of unsafe stacks for threads that are exiting. We delay
+/// unmapping them until the thread exits.
+static thread_stack_ll *thread_stacks = nullptr;
+static pthread_mutex_t thread_stacks_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/// Thread-specific data destructor. We want to free the unsafe stack only after
+/// this thread is terminated. libc can call functions in safestack-instrumented
+/// code (like free) after thread-specific data destructors have run.
static void thread_cleanup_handler(void *_iter) {
- // We want to free the unsafe stack only after all other destructors
- // have already run. We force this function to be called multiple times.
- // User destructors that might run more then PTHREAD_DESTRUCTOR_ITERATIONS-1
- // times might still end up executing after the unsafe stack is deallocated.
- size_t iter = (size_t)_iter;
- if (iter < PTHREAD_DESTRUCTOR_ITERATIONS) {
- pthread_setspecific(thread_cleanup_key, (void *)(iter + 1));
- } else {
- // This is the last iteration
- unsafe_stack_free();
+ CHECK_NE(unsafe_stack_start, nullptr);
+ pthread_setspecific(thread_cleanup_key, NULL);
+
+ pthread_mutex_lock(&thread_stacks_mutex);
+ // Temporary list to hold the previous threads stacks so we don't hold the
+ // thread_stacks_mutex for long.
+ thread_stack_ll *temp_stacks = thread_stacks;
+ thread_stacks = nullptr;
+ pthread_mutex_unlock(&thread_stacks_mutex);
+
+ pid_t pid = getpid();
+ tid_t tid = GetTid();
+
+ // Free stacks for dead threads
+ thread_stack_ll **stackp = &temp_stacks;
+ while (*stackp) {
+ thread_stack_ll *stack = *stackp;
+ int error;
+ if (stack->pid != pid ||
+ (internal_iserror(TgKill(stack->pid, stack->tid, 0), &error) &&
+ error == ESRCH)) {
+ UnmapOrDie(stack->stack_base, stack->size);
+ *stackp = stack->next;
+ free(stack);
+ } else
+ stackp = &stack->next;
}
+
+ thread_stack_ll *cur_stack =
+ (thread_stack_ll *)malloc(sizeof(thread_stack_ll));
+ cur_stack->stack_base = (char *)unsafe_stack_start - unsafe_stack_guard;
+ cur_stack->size = unsafe_stack_size + unsafe_stack_guard;
+ cur_stack->pid = pid;
+ cur_stack->tid = tid;
+
+ pthread_mutex_lock(&thread_stacks_mutex);
+ // Merge thread_stacks with the current thread's stack and any remaining
+ // temp_stacks
+ *stackp = thread_stacks;
+ cur_stack->next = temp_stacks;
+ thread_stacks = cur_stack;
+ pthread_mutex_unlock(&thread_stacks_mutex);
+
+ unsafe_stack_start = nullptr;
}
static void EnsureInterceptorsInitialized();
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index 1be99616e232..f7bf4b009720 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -16,8 +16,10 @@ set(SANITIZER_SOURCES_NOTERMINATION
sanitizer_linux.cc
sanitizer_linux_s390.cc
sanitizer_mac.cc
+ sanitizer_netbsd.cc
sanitizer_openbsd.cc
sanitizer_persistent_allocator.cc
+ sanitizer_platform_limits_freebsd.cc
sanitizer_platform_limits_linux.cc
sanitizer_platform_limits_netbsd.cc
sanitizer_platform_limits_openbsd.cc
@@ -36,6 +38,7 @@ set(SANITIZER_SOURCES_NOTERMINATION
sanitizer_suppressions.cc
sanitizer_tls_get_addr.cc
sanitizer_thread_registry.cc
+ sanitizer_type_traits.cc
sanitizer_win.cc)
if(UNIX AND NOT APPLE AND NOT OS_NAME MATCHES "SunOS")
@@ -143,6 +146,7 @@ set(SANITIZER_IMPL_HEADERS
sanitizer_libignore.h
sanitizer_linux.h
sanitizer_list.h
+ sanitizer_local_address_space_view.h
sanitizer_mac.h
sanitizer_malloc_mac.inc
sanitizer_mutex.h
@@ -158,6 +162,7 @@ set(SANITIZER_IMPL_HEADERS
sanitizer_procmaps.h
sanitizer_quarantine.h
sanitizer_report_decorator.h
+ sanitizer_ring_buffer.h
sanitizer_rtems.h
sanitizer_signal_interceptors.inc
sanitizer_stackdepot.h
@@ -187,11 +192,8 @@ set(SANITIZER_IMPL_HEADERS
include_directories(..)
-set(SANITIZER_COMMON_DEFINITIONS)
-
-include(CheckIncludeFile)
-append_have_file_definition(rpc/xdr.h HAVE_RPC_XDR_H SANITIZER_COMMON_DEFINITIONS)
-append_have_file_definition(tirpc/rpc/xdr.h HAVE_TIRPC_RPC_XDR_H SANITIZER_COMMON_DEFINITIONS)
+set(SANITIZER_COMMON_DEFINITIONS
+ HAVE_RPC_XDR_H=${HAVE_RPC_XDR_H})
set(SANITIZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
append_rtti_flag(OFF SANITIZER_CFLAGS)
diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h
index 9655a2264f34..88017160acf9 100644
--- a/lib/sanitizer_common/sanitizer_allocator.h
+++ b/lib/sanitizer_common/sanitizer_allocator.h
@@ -14,13 +14,15 @@
#ifndef SANITIZER_ALLOCATOR_H
#define SANITIZER_ALLOCATOR_H
-#include "sanitizer_internal_defs.h"
#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_lfstack.h"
#include "sanitizer_libc.h"
#include "sanitizer_list.h"
+#include "sanitizer_local_address_space_view.h"
#include "sanitizer_mutex.h"
-#include "sanitizer_lfstack.h"
#include "sanitizer_procmaps.h"
+#include "sanitizer_type_traits.h"
namespace __sanitizer {
diff --git a/lib/sanitizer_common/sanitizer_allocator_bytemap.h b/lib/sanitizer_common/sanitizer_allocator_bytemap.h
index 7df3e4097bf2..ef26941fe609 100644
--- a/lib/sanitizer_common/sanitizer_allocator_bytemap.h
+++ b/lib/sanitizer_common/sanitizer_allocator_bytemap.h
@@ -15,9 +15,10 @@
#endif
// Maps integers in rage [0, kSize) to u8 values.
-template<u64 kSize>
+template <u64 kSize, typename AddressSpaceViewTy = LocalAddressSpaceView>
class FlatByteMap {
public:
+ using AddressSpaceView = AddressSpaceViewTy;
void Init() {
internal_memset(map_, 0, sizeof(map_));
}
@@ -41,9 +42,12 @@ class FlatByteMap {
// to kSize2-byte arrays. The secondary arrays are mmaped on demand.
// Each value is initially zero and can be set to something else only once.
// Setting and getting values from multiple threads is safe w/o extra locking.
-template <u64 kSize1, u64 kSize2, class MapUnmapCallback = NoOpMapUnmapCallback>
+template <u64 kSize1, u64 kSize2,
+ typename AddressSpaceViewTy = LocalAddressSpaceView,
+ class MapUnmapCallback = NoOpMapUnmapCallback>
class TwoLevelByteMap {
public:
+ using AddressSpaceView = AddressSpaceViewTy;
void Init() {
internal_memset(map1_, 0, sizeof(map1_));
mu_.Init();
@@ -73,7 +77,8 @@ class TwoLevelByteMap {
CHECK_LT(idx, kSize1 * kSize2);
u8 *map2 = Get(idx / kSize2);
if (!map2) return 0;
- return map2[idx % kSize2];
+ auto value_ptr = AddressSpaceView::Load(&map2[idx % kSize2]);
+ return *value_ptr;
}
private:
diff --git a/lib/sanitizer_common/sanitizer_allocator_combined.h b/lib/sanitizer_common/sanitizer_allocator_combined.h
index 1f874d60b92b..fcc4469c98cf 100644
--- a/lib/sanitizer_common/sanitizer_allocator_combined.h
+++ b/lib/sanitizer_common/sanitizer_allocator_combined.h
@@ -21,19 +21,28 @@
// PrimaryAllocator is used via a local AllocatorCache.
// SecondaryAllocator can allocate anything, but is not efficient.
template <class PrimaryAllocator, class AllocatorCache,
- class SecondaryAllocator> // NOLINT
+ class SecondaryAllocator,
+ typename AddressSpaceViewTy = LocalAddressSpaceView> // NOLINT
class CombinedAllocator {
public:
+ using AddressSpaceView = AddressSpaceViewTy;
+ static_assert(is_same<AddressSpaceView,
+ typename PrimaryAllocator::AddressSpaceView>::value,
+ "PrimaryAllocator is using wrong AddressSpaceView");
+ static_assert(is_same<AddressSpaceView,
+ typename SecondaryAllocator::AddressSpaceView>::value,
+ "SecondaryAllocator is using wrong AddressSpaceView");
+
void InitLinkerInitialized(s32 release_to_os_interval_ms) {
+ stats_.InitLinkerInitialized();
primary_.Init(release_to_os_interval_ms);
secondary_.InitLinkerInitialized();
- stats_.InitLinkerInitialized();
}
void Init(s32 release_to_os_interval_ms) {
+ stats_.Init();
primary_.Init(release_to_os_interval_ms);
secondary_.Init();
- stats_.Init();
}
void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) {
@@ -194,4 +203,3 @@ class CombinedAllocator {
SecondaryAllocator secondary_;
AllocatorGlobalStats stats_;
};
-
diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h
index c0c03d3f4345..30fc7042b6b5 100644
--- a/lib/sanitizer_common/sanitizer_allocator_internal.h
+++ b/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -37,7 +37,8 @@ struct AP32 {
static const uptr kMetadataSize = 0;
typedef InternalSizeClassMap SizeClassMap;
static const uptr kRegionSizeLog = kInternalAllocatorRegionSizeLog;
- typedef __sanitizer::ByteMap ByteMap;
+ using AddressSpaceView = LocalAddressSpaceView;
+ using ByteMap = __sanitizer::ByteMap;
typedef NoOpMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
};
diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h
index 67970e95b31e..abaac3d1a70b 100644
--- a/lib/sanitizer_common/sanitizer_allocator_primary32.h
+++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h
@@ -48,6 +48,7 @@ struct SizeClassAllocator32FlagMasks { // Bit masks.
template <class Params>
class SizeClassAllocator32 {
public:
+ using AddressSpaceView = typename Params::AddressSpaceView;
static const uptr kSpaceBeg = Params::kSpaceBeg;
static const u64 kSpaceSize = Params::kSpaceSize;
static const uptr kMetadataSize = Params::kMetadataSize;
@@ -56,6 +57,10 @@ class SizeClassAllocator32 {
typedef typename Params::ByteMap ByteMap;
typedef typename Params::MapUnmapCallback MapUnmapCallback;
+ static_assert(
+ is_same<typename ByteMap::AddressSpaceView, AddressSpaceView>::value,
+ "AddressSpaceView type mismatch");
+
static const bool kRandomShuffleChunks = Params::kFlags &
SizeClassAllocator32FlagMasks::kRandomShuffleChunks;
static const bool kUseSeparateSizeClassForBatch = Params::kFlags &
diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h
index 6acb4f8bc56d..b063bf0d302f 100644
--- a/lib/sanitizer_common/sanitizer_allocator_primary64.h
+++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h
@@ -46,6 +46,7 @@ struct SizeClassAllocator64FlagMasks { // Bit masks.
template <class Params>
class SizeClassAllocator64 {
public:
+ using AddressSpaceView = typename Params::AddressSpaceView;
static const uptr kSpaceBeg = Params::kSpaceBeg;
static const uptr kSpaceSize = Params::kSpaceSize;
static const uptr kMetadataSize = Params::kMetadataSize;
@@ -294,8 +295,10 @@ class SizeClassAllocator64 {
RegionInfo *region = GetRegionInfo(class_id);
uptr chunk_size = ClassIdToSize(class_id);
uptr region_beg = SpaceBeg() + class_id * kRegionSize;
+ uptr region_allocated_user_size =
+ AddressSpaceView::Load(region)->allocated_user;
for (uptr chunk = region_beg;
- chunk < region_beg + region->allocated_user;
+ chunk < region_beg + region_allocated_user_size;
chunk += chunk_size) {
// Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
callback(chunk, arg);
diff --git a/lib/sanitizer_common/sanitizer_allocator_secondary.h b/lib/sanitizer_common/sanitizer_allocator_secondary.h
index ab680b5e2d11..0c8505c34c87 100644
--- a/lib/sanitizer_common/sanitizer_allocator_secondary.h
+++ b/lib/sanitizer_common/sanitizer_allocator_secondary.h
@@ -68,9 +68,11 @@ typedef LargeMmapAllocatorPtrArrayDynamic DefaultLargeMmapAllocatorPtrArray;
// The main purpose of this allocator is to cover large and rare allocation
// sizes not covered by more efficient allocators (e.g. SizeClassAllocator64).
template <class MapUnmapCallback = NoOpMapUnmapCallback,
- class PtrArrayT = DefaultLargeMmapAllocatorPtrArray>
+ class PtrArrayT = DefaultLargeMmapAllocatorPtrArray,
+ class AddressSpaceViewTy = LocalAddressSpaceView>
class LargeMmapAllocator {
public:
+ using AddressSpaceView = AddressSpaceViewTy;
void InitLinkerInitialized() {
page_size_ = GetPageSizeCached();
chunks_ = reinterpret_cast<Header**>(ptr_array_.Init());
@@ -202,9 +204,10 @@ class LargeMmapAllocator {
void EnsureSortedChunks() {
if (chunks_sorted_) return;
- Sort(reinterpret_cast<uptr *>(chunks_), n_chunks_);
+ Header **chunks = AddressSpaceView::LoadWritable(chunks_, n_chunks_);
+ Sort(reinterpret_cast<uptr *>(chunks), n_chunks_);
for (uptr i = 0; i < n_chunks_; i++)
- chunks_[i]->chunk_idx = i;
+ AddressSpaceView::LoadWritable(chunks[i])->chunk_idx = i;
chunks_sorted_ = true;
}
@@ -272,12 +275,13 @@ class LargeMmapAllocator {
// The allocator must be locked when calling this function.
void ForEachChunk(ForEachChunkCallback callback, void *arg) {
EnsureSortedChunks(); // Avoid doing the sort while iterating.
+ const Header *const *chunks = AddressSpaceView::Load(chunks_, n_chunks_);
for (uptr i = 0; i < n_chunks_; i++) {
- auto t = chunks_[i];
+ const Header *t = chunks[i];
callback(reinterpret_cast<uptr>(GetUser(t)), arg);
// Consistency check: verify that the array did not change.
- CHECK_EQ(chunks_[i], t);
- CHECK_EQ(chunks_[i]->chunk_idx, i);
+ CHECK_EQ(chunks[i], t);
+ CHECK_EQ(AddressSpaceView::Load(chunks[i])->chunk_idx, i);
}
}
@@ -297,7 +301,7 @@ class LargeMmapAllocator {
return GetHeader(reinterpret_cast<uptr>(p));
}
- void *GetUser(Header *h) {
+ void *GetUser(const Header *h) {
CHECK(IsAligned((uptr)h, page_size_));
return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + page_size_);
}
@@ -316,4 +320,3 @@ class LargeMmapAllocator {
} stats;
StaticSpinMutex mutex_;
};
-
diff --git a/lib/sanitizer_common/sanitizer_allocator_size_class_map.h b/lib/sanitizer_common/sanitizer_allocator_size_class_map.h
index 77ab4fb544a2..1c05fb8ff06b 100644
--- a/lib/sanitizer_common/sanitizer_allocator_size_class_map.h
+++ b/lib/sanitizer_common/sanitizer_allocator_size_class_map.h
@@ -232,3 +232,11 @@ class SizeClassMap {
typedef SizeClassMap<3, 4, 8, 17, 128, 16> DefaultSizeClassMap;
typedef SizeClassMap<3, 4, 8, 17, 64, 14> CompactSizeClassMap;
typedef SizeClassMap<2, 5, 9, 16, 64, 14> VeryCompactSizeClassMap;
+
+// The following SizeClassMap only holds a way small number of cached entries,
+// allowing for denser per-class arrays, smaller memory footprint and usually
+// better performances in threaded environments.
+typedef SizeClassMap<3, 4, 8, 17, 8, 10> DenseSizeClassMap;
+// Similar to VeryCompact map above, this one has a small number of different
+// size classes, and also reduced thread-local caches.
+typedef SizeClassMap<2, 5, 9, 16, 8, 10> VeryDenseSizeClassMap;
diff --git a/lib/sanitizer_common/sanitizer_atomic_clang_x86.h b/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
index 38feb29287f1..195533ea2320 100644
--- a/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
+++ b/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
@@ -61,8 +61,7 @@ INLINE typename T::Type atomic_load(
"emms;" // Empty mmx state/Reset FP regs
: "=m" (v)
: "m" (a->val_dont_use)
- : // mark the FP stack and mmx registers as clobbered
- "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+ : // mark the mmx registers as clobbered
#ifdef __MMX__
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
#endif // #ifdef __MMX__
@@ -100,8 +99,7 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
"emms;" // Empty mmx state/Reset FP regs
: "=m" (a->val_dont_use)
: "m" (v)
- : // mark the FP stack and mmx registers as clobbered
- "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+ : // mark the mmx registers as clobbered
#ifdef __MMX__
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
#endif // #ifdef __MMX__
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 7d72b0cfe4ce..6868961902ce 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -339,11 +339,6 @@ int __sanitizer_acquire_crash_state() {
}
SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_set_death_callback(void (*callback)(void)) {
- SetUserDieCallback(callback);
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
uptr),
void (*free_hook)(const void *)) {
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 3b999edfbe58..d0aebd994129 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -61,6 +61,15 @@ INLINE int Verbosity() {
return atomic_load(&current_verbosity, memory_order_relaxed);
}
+#if SANITIZER_ANDROID
+INLINE uptr GetPageSize() {
+// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array.
+ return 4096;
+}
+INLINE uptr GetPageSizeCached() {
+ return 4096;
+}
+#else
uptr GetPageSize();
extern uptr PageSizeCached;
INLINE uptr GetPageSizeCached() {
@@ -68,11 +77,13 @@ INLINE uptr GetPageSizeCached() {
PageSizeCached = GetPageSize();
return PageSizeCached;
}
+#endif
uptr GetMmapGranularity();
uptr GetMaxVirtualAddress();
uptr GetMaxUserVirtualAddress();
// Threads
tid_t GetTid();
+int TgKill(pid_t pid, tid_t tid, int sig);
uptr GetThreadSelf();
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
uptr *stack_bottom);
@@ -222,7 +233,9 @@ bool SetEnv(const char *name, const char *value);
u32 GetUid();
void ReExec();
void CheckASLR();
+void CheckMPROTECT();
char **GetArgv();
+char **GetEnviron();
void PrintCmdline();
bool StackSizeIsUnlimited();
uptr GetStackSizeLimitInBytes();
@@ -896,6 +909,7 @@ struct SignalContext {
bool IsMemoryAccess() const;
};
+void InitializePlatformEarly();
void MaybeReexec();
template <typename Fn>
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index ff18bc801749..50f7837747e6 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -77,7 +77,15 @@
#define ctime __ctime50
#define ctime_r __ctime_r50
#define devname __devname50
+#define fgetpos __fgetpos50
+#define fsetpos __fsetpos50
+#define fts_children __fts_children60
+#define fts_close __fts_close60
+#define fts_open __fts_open60
+#define fts_read __fts_read60
+#define fts_set __fts_set60
#define getitimer __getitimer50
+#define getmntinfo __getmntinfo13
#define getpwent __getpwent50
#define getpwnam __getpwnam50
#define getpwnam_r __getpwnam_r50
@@ -87,6 +95,7 @@
#define getutxent __getutxent50
#define getutxid __getutxid50
#define getutxline __getutxline50
+#define pututxline __pututxline50
#define glob __glob30
#define gmtime __gmtime50
#define gmtime_r __gmtime_r50
@@ -109,6 +118,7 @@
#define stat __stat50
#define time __time50
#define times __times13
+#define unvis __unvis50
#define wait3 __wait350
#define wait4 __wait450
extern const unsigned short *_ctype_tab_;
@@ -1810,7 +1820,10 @@ INTERCEPTOR(int, ioctl, int d, unsigned long request, ...) {
#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS || \
SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT || \
- SANITIZER_INTERCEPT_GETPWENT_R || SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
+ SANITIZER_INTERCEPT_GETPWENT_R || \
+ SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS || \
+ SANITIZER_INTERCEPT_FGETPWENT_R || \
+ SANITIZER_INTERCEPT_FGETGRENT_R
static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) {
if (pwd) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, sizeof(*pwd));
@@ -2034,36 +2047,51 @@ INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf,
if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
return res;
}
-INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf,
- SIZE_T buflen, __sanitizer_passwd **pwbufp) {
+INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen,
+ __sanitizer_group **pwbufp) {
void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent_r, fp, pwbuf, buf, buflen, pwbufp);
+ COMMON_INTERCEPTOR_ENTER(ctx, getgrent_r, pwbuf, buf, buflen, pwbufp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
- int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp);
+ int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp);
if (!res) {
- if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
+ if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
return res;
}
-INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen,
- __sanitizer_group **pwbufp) {
+#define INIT_GETPWENT_R \
+ COMMON_INTERCEPT_FUNCTION(getpwent_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrent_r);
+#else
+#define INIT_GETPWENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_FGETPWENT_R
+INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf,
+ SIZE_T buflen, __sanitizer_passwd **pwbufp) {
void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, getgrent_r, pwbuf, buf, buflen, pwbufp);
+ COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent_r, fp, pwbuf, buf, buflen, pwbufp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
- int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp);
+ int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp);
if (!res) {
- if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
+ if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
return res;
}
+#define INIT_FGETPWENT_R \
+ COMMON_INTERCEPT_FUNCTION(fgetpwent_r);
+#else
+#define INIT_FGETPWENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_FGETGRENT_R
INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf,
SIZE_T buflen, __sanitizer_group **pwbufp) {
void *ctx;
@@ -2079,13 +2107,10 @@ INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf,
if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
return res;
}
-#define INIT_GETPWENT_R \
- COMMON_INTERCEPT_FUNCTION(getpwent_r); \
- COMMON_INTERCEPT_FUNCTION(fgetpwent_r); \
- COMMON_INTERCEPT_FUNCTION(getgrent_r); \
+#define INIT_FGETGRENT_R \
COMMON_INTERCEPT_FUNCTION(fgetgrent_r);
#else
-#define INIT_GETPWENT_R
+#define INIT_FGETGRENT_R
#endif
#if SANITIZER_INTERCEPT_SETPWENT
@@ -2149,6 +2174,8 @@ INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
namespace __sanitizer {
extern "C" {
int real_clock_gettime(u32 clk_id, void *tp) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_clock_gettime(clk_id, tp);
return REAL(clock_gettime)(clk_id, tp);
}
} // extern "C"
@@ -3345,14 +3372,14 @@ INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
return res;
}
-INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
+INTERCEPTOR(UINTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
char *real_endptr;
- INTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base);
+ UINTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base);
StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
return res;
}
@@ -4254,11 +4281,16 @@ INTERCEPTOR(int, statvfs, char *path, void *buf) {
INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
int res = REAL(fstatvfs)(fd, buf);
- if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ if (fd >= 0)
+ COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ }
return res;
}
#define INIT_STATVFS \
@@ -4460,6 +4492,7 @@ INTERCEPTOR(int, random_r, void *buf, u32 *result) {
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED || \
SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED || \
SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GET || \
SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GET || \
@@ -4818,6 +4851,14 @@ INTERCEPTOR(float, remquof, float x, float y, int *quo) {
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
}
+#define INIT_REMQUO \
+ COMMON_INTERCEPT_FUNCTION(remquo); \
+ COMMON_INTERCEPT_FUNCTION(remquof);
+#else
+#define INIT_REMQUO
+#endif
+
+#if SANITIZER_INTERCEPT_REMQUOL
INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo);
@@ -4828,12 +4869,10 @@ INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) {
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
}
-#define INIT_REMQUO \
- COMMON_INTERCEPT_FUNCTION(remquo); \
- COMMON_INTERCEPT_FUNCTION(remquof); \
+#define INIT_REMQUOL \
COMMON_INTERCEPT_FUNCTION_LDBL(remquol);
#else
-#define INIT_REMQUO
+#define INIT_REMQUOL
#endif
#if SANITIZER_INTERCEPT_LGAMMA
@@ -4852,6 +4891,14 @@ INTERCEPTOR(float, lgammaf, float x) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
return res;
}
+#define INIT_LGAMMA \
+ COMMON_INTERCEPT_FUNCTION(lgamma); \
+ COMMON_INTERCEPT_FUNCTION(lgammaf);
+#else
+#define INIT_LGAMMA
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMAL
INTERCEPTOR(long double, lgammal, long double x) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, lgammal, x);
@@ -4859,12 +4906,10 @@ INTERCEPTOR(long double, lgammal, long double x) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
return res;
}
-#define INIT_LGAMMA \
- COMMON_INTERCEPT_FUNCTION(lgamma); \
- COMMON_INTERCEPT_FUNCTION(lgammaf); \
+#define INIT_LGAMMAL \
COMMON_INTERCEPT_FUNCTION_LDBL(lgammal);
#else
-#define INIT_LGAMMA
+#define INIT_LGAMMAL
#endif
#if SANITIZER_INTERCEPT_LGAMMA_R
@@ -5650,9 +5695,15 @@ INTERCEPTOR(void *, tsearch, void *key, void **rootp,
void unpoison_file(__sanitizer_FILE *fp) {
#if SANITIZER_HAS_STRUCT_FILE
COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp, sizeof(*fp));
+#if SANITIZER_NETBSD
+ if (fp->_bf._base && fp->_bf._size > 0)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_bf._base,
+ fp->_bf._size);
+#else
if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base,
fp->_IO_read_end - fp->_IO_read_base);
+#endif
#endif // SANITIZER_HAS_STRUCT_FILE
}
#endif
@@ -6522,10 +6573,21 @@ INTERCEPTOR(void *, getutxline, void *ut) {
COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmpx_sz);
return res;
}
+INTERCEPTOR(void *, pututxline, const void *ut) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pututxline, ut);
+ if (ut)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, ut, __sanitizer::struct_utmpx_sz);
+ void *res = REAL(pututxline)(ut);
+ if (res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, __sanitizer::struct_utmpx_sz);
+ return res;
+}
#define INIT_UTMPX \
COMMON_INTERCEPT_FUNCTION(getutxent); \
COMMON_INTERCEPT_FUNCTION(getutxid); \
- COMMON_INTERCEPT_FUNCTION(getutxline);
+ COMMON_INTERCEPT_FUNCTION(getutxline); \
+ COMMON_INTERCEPT_FUNCTION(pututxline);
#else
#define INIT_UTMPX
#endif
@@ -7017,12 +7079,19 @@ INTERCEPTOR(char *, devname, u64 dev, u32 type) {
#endif
#if SANITIZER_INTERCEPT_DEVNAME_R
-INTERCEPTOR(int, devname_r, u64 dev, u32 type, char *path, uptr len) {
+#if SANITIZER_NETBSD
+#define DEVNAME_R_RETTYPE int
+#define DEVNAME_R_SUCCESS(x) (!(x))
+#else
+#define DEVNAME_R_RETTYPE char*
+#define DEVNAME_R_SUCCESS(x) (x)
+#endif
+INTERCEPTOR(DEVNAME_R_RETTYPE, devname_r, u64 dev, u32 type, char *path,
+ uptr len) {
void *ctx;
- int res;
COMMON_INTERCEPTOR_ENTER(ctx, devname_r, dev, type, path, len);
- res = REAL(devname_r)(dev, type, path, len);
- if (!res)
+ DEVNAME_R_RETTYPE res = REAL(devname_r)(dev, type, path, len);
+ if (DEVNAME_R_SUCCESS(res))
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, path, REAL(strlen)(path) + 1);
return res;
}
@@ -7234,9 +7303,2174 @@ INTERCEPTOR(struct __sanitizer_netent *, getnetbyaddr, u32 net, int type) {
#define INIT_NETENT
#endif
+#if SANITIZER_INTERCEPT_GETMNTINFO
+INTERCEPTOR(int, getmntinfo, void **mntbufp, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getmntinfo, mntbufp, flags);
+ int cnt = REAL(getmntinfo)(mntbufp, flags);
+ if (cnt > 0 && mntbufp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mntbufp, sizeof(void *));
+ if (*mntbufp)
+#if SANITIZER_NETBSD
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statvfs_sz);
+#else
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statfs_sz);
+#endif
+ }
+ return cnt;
+}
+#define INIT_GETMNTINFO COMMON_INTERCEPT_FUNCTION(getmntinfo)
+#else
+#define INIT_GETMNTINFO
+#endif
+
+#if SANITIZER_INTERCEPT_MI_VECTOR_HASH
+INTERCEPTOR(void, mi_vector_hash, const void *key, SIZE_T len, u32 seed,
+ u32 hashes[3]) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, mi_vector_hash, key, len, seed, hashes);
+ if (key)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, key, len);
+ REAL(mi_vector_hash)(key, len, seed, hashes);
+ if (hashes)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hashes, sizeof(hashes[0]) * 3);
+}
+#define INIT_MI_VECTOR_HASH COMMON_INTERCEPT_FUNCTION(mi_vector_hash)
+#else
+#define INIT_MI_VECTOR_HASH
+#endif
+
+#if SANITIZER_INTERCEPT_SETVBUF
+INTERCEPTOR(int, setvbuf, __sanitizer_FILE *stream, char *buf, int mode,
+ SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setvbuf, stream, buf, mode, size);
+ int ret = REAL(setvbuf)(stream, buf, mode, size);
+ if (buf)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, size);
+ if (stream)
+ unpoison_file(stream);
+ return ret;
+}
+
+INTERCEPTOR(void, setbuf, __sanitizer_FILE *stream, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setbuf, stream, buf);
+ REAL(setbuf)(stream, buf);
+ if (buf) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer_bufsiz);
+ }
+ if (stream)
+ unpoison_file(stream);
+}
+
+INTERCEPTOR(void, setbuffer, __sanitizer_FILE *stream, char *buf, int mode) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setbuffer, stream, buf, mode);
+ REAL(setbuffer)(stream, buf, mode);
+ if (buf) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer_bufsiz);
+ }
+ if (stream)
+ unpoison_file(stream);
+}
+
+INTERCEPTOR(void, setlinebuf, __sanitizer_FILE *stream) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, setlinebuf, stream);
+ REAL(setlinebuf)(stream);
+ if (stream)
+ unpoison_file(stream);
+}
+#define INIT_SETVBUF COMMON_INTERCEPT_FUNCTION(setvbuf); \
+ COMMON_INTERCEPT_FUNCTION(setbuf); \
+ COMMON_INTERCEPT_FUNCTION(setbuffer); \
+ COMMON_INTERCEPT_FUNCTION(setlinebuf)
+#else
+#define INIT_SETVBUF
+#endif
+
+#if SANITIZER_INTERCEPT_GETVFSSTAT
+INTERCEPTOR(int, getvfsstat, void *buf, SIZE_T bufsize, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getvfsstat, buf, bufsize, flags);
+ int ret = REAL(getvfsstat)(buf, bufsize, flags);
+ if (buf && ret > 0)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, ret * struct_statvfs_sz);
+ return ret;
+}
+#define INIT_GETVFSSTAT COMMON_INTERCEPT_FUNCTION(getvfsstat)
+#else
+#define INIT_GETVFSSTAT
+#endif
+
+#if SANITIZER_INTERCEPT_REGEX
+INTERCEPTOR(int, regcomp, void *preg, const char *pattern, int cflags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, regcomp, preg, pattern, cflags);
+ if (pattern)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, pattern, REAL(strlen)(pattern) + 1);
+ int res = REAL(regcomp)(preg, pattern, cflags);
+ if (!res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, preg, struct_regex_sz);
+ return res;
+}
+INTERCEPTOR(int, regexec, const void *preg, const char *string, SIZE_T nmatch,
+ struct __sanitizer_regmatch *pmatch[], int eflags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, regexec, preg, string, nmatch, pmatch, eflags);
+ if (preg)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz);
+ if (string)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, string, REAL(strlen)(string) + 1);
+ int res = REAL(regexec)(preg, string, nmatch, pmatch, eflags);
+ if (!res && pmatch)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pmatch, nmatch * struct_regmatch_sz);
+ return res;
+}
+INTERCEPTOR(SIZE_T, regerror, int errcode, const void *preg, char *errbuf,
+ SIZE_T errbuf_size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, regerror, errcode, preg, errbuf, errbuf_size);
+ if (preg)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz);
+ SIZE_T res = REAL(regerror)(errcode, preg, errbuf, errbuf_size);
+ if (errbuf)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, errbuf, REAL(strlen)(errbuf) + 1);
+ return res;
+}
+INTERCEPTOR(void, regfree, const void *preg) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, regfree, preg);
+ if (preg)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz);
+ REAL(regfree)(preg);
+}
+#define INIT_REGEX \
+ COMMON_INTERCEPT_FUNCTION(regcomp); \
+ COMMON_INTERCEPT_FUNCTION(regexec); \
+ COMMON_INTERCEPT_FUNCTION(regerror); \
+ COMMON_INTERCEPT_FUNCTION(regfree);
+#else
+#define INIT_REGEX
+#endif
+
+#if SANITIZER_INTERCEPT_REGEXSUB
+INTERCEPTOR(SSIZE_T, regnsub, char *buf, SIZE_T bufsiz, const char *sub,
+ const struct __sanitizer_regmatch *rm, const char *str) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, regnsub, buf, bufsiz, sub, rm, str);
+ if (sub)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, sub, REAL(strlen)(sub) + 1);
+ // The implementation demands and hardcodes 10 elements
+ if (rm)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, rm, 10 * struct_regmatch_sz);
+ if (str)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1);
+ SSIZE_T res = REAL(regnsub)(buf, bufsiz, sub, rm, str);
+ if (res > 0 && buf)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ return res;
+}
+INTERCEPTOR(SSIZE_T, regasub, char **buf, const char *sub,
+ const struct __sanitizer_regmatch *rm, const char *sstr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, regasub, buf, sub, rm, sstr);
+ if (sub)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, sub, REAL(strlen)(sub) + 1);
+ // Hardcode 10 elements as this is hardcoded size
+ if (rm)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, rm, 10 * struct_regmatch_sz);
+ if (sstr)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, sstr, REAL(strlen)(sstr) + 1);
+ SSIZE_T res = REAL(regasub)(buf, sub, rm, sstr);
+ if (res > 0 && buf) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sizeof(char *));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *buf, REAL(strlen)(*buf) + 1);
+ }
+ return res;
+}
+
+#define INIT_REGEXSUB \
+ COMMON_INTERCEPT_FUNCTION(regnsub); \
+ COMMON_INTERCEPT_FUNCTION(regasub);
+#else
+#define INIT_REGEXSUB
+#endif
+
+#if SANITIZER_INTERCEPT_FTS
+INTERCEPTOR(void *, fts_open, char *const *path_argv, int options,
+ int (*compar)(void **, void **)) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fts_open, path_argv, options, compar);
+ if (path_argv) {
+ for (char *const *pa = path_argv; ; ++pa) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, pa, sizeof(char **));
+ if (!*pa)
+ break;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, *pa, REAL(strlen)(*pa) + 1);
+ }
+ }
+ // TODO(kamil): handle compar callback
+ void *fts = REAL(fts_open)(path_argv, options, compar);
+ if (fts)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, fts, struct_FTS_sz);
+ return fts;
+}
+
+INTERCEPTOR(void *, fts_read, void *ftsp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fts_read, ftsp);
+ if (ftsp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz);
+ void *ftsent = REAL(fts_read)(ftsp);
+ if (ftsent)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ftsent, struct_FTSENT_sz);
+ return ftsent;
+}
+
+INTERCEPTOR(void *, fts_children, void *ftsp, int options) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fts_children, ftsp, options);
+ if (ftsp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz);
+ void *ftsent = REAL(fts_children)(ftsp, options);
+ if (ftsent)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ftsent, struct_FTSENT_sz);
+ return ftsent;
+}
+
+INTERCEPTOR(int, fts_set, void *ftsp, void *f, int options) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fts_set, ftsp, f, options);
+ if (ftsp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz);
+ if (f)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, f, struct_FTSENT_sz);
+ return REAL(fts_set)(ftsp, f, options);
+}
+
+INTERCEPTOR(int, fts_close, void *ftsp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fts_close, ftsp);
+ if (ftsp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz);
+ return REAL(fts_close)(ftsp);
+}
+#define INIT_FTS \
+ COMMON_INTERCEPT_FUNCTION(fts_open); \
+ COMMON_INTERCEPT_FUNCTION(fts_read); \
+ COMMON_INTERCEPT_FUNCTION(fts_children); \
+ COMMON_INTERCEPT_FUNCTION(fts_set); \
+ COMMON_INTERCEPT_FUNCTION(fts_close);
+#else
+#define INIT_FTS
+#endif
+
+#if SANITIZER_INTERCEPT_SYSCTL
+INTERCEPTOR(int, sysctl, int *name, unsigned int namelen, void *oldp,
+ SIZE_T *oldlenp, void *newp, SIZE_T newlen) {
+ void *ctx;
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_sysctl(name, namelen, oldp, oldlenp, newp, newlen);
+ COMMON_INTERCEPTOR_ENTER(ctx, sysctl, name, namelen, oldp, oldlenp, newp,
+ newlen);
+ if (name)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, namelen * sizeof(*name));
+ if (oldlenp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, oldlenp, sizeof(*oldlenp));
+ if (newp && newlen)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, newp, newlen);
+ int res = REAL(sysctl)(name, namelen, oldp, oldlenp, newp, newlen);
+ if (!res) {
+ if (oldlenp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldlenp, sizeof(*oldlenp));
+ if (oldp)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldp, *oldlenp);
+ }
+ }
+ return res;
+}
+
+INTERCEPTOR(int, sysctlbyname, char *sname, void *oldp, SIZE_T *oldlenp,
+ void *newp, SIZE_T newlen) {
+ void *ctx;
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_sysctlbyname(sname, oldp, oldlenp, newp, newlen);
+ COMMON_INTERCEPTOR_ENTER(ctx, sysctlbyname, sname, oldp, oldlenp, newp,
+ newlen);
+ if (sname)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1);
+ if (oldlenp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, oldlenp, sizeof(*oldlenp));
+ if (newp && newlen)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, newp, newlen);
+ int res = REAL(sysctlbyname)(sname, oldp, oldlenp, newp, newlen);
+ if (!res) {
+ if (oldlenp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldlenp, sizeof(*oldlenp));
+ if (oldp)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldp, *oldlenp);
+ }
+ }
+ return res;
+}
+
+INTERCEPTOR(int, sysctlnametomib, const char *sname, int *name,
+ SIZE_T *namelenp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sysctlnametomib, sname, name, namelenp);
+ if (sname)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1);
+ if (namelenp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, namelenp, sizeof(*namelenp));
+ int res = REAL(sysctlnametomib)(sname, name, namelenp);
+ if (!res) {
+ if (namelenp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelenp, sizeof(*namelenp));
+ if (name)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, *namelenp * sizeof(*name));
+ }
+ }
+ return res;
+}
+
+#define INIT_SYSCTL \
+ COMMON_INTERCEPT_FUNCTION(sysctl); \
+ COMMON_INTERCEPT_FUNCTION(sysctlbyname); \
+ COMMON_INTERCEPT_FUNCTION(sysctlnametomib);
+#else
+#define INIT_SYSCTL
+#endif
+
+#if SANITIZER_INTERCEPT_ASYSCTL
+INTERCEPTOR(void *, asysctl, const int *name, SIZE_T namelen, SIZE_T *len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, asysctl, name, namelen, len);
+ if (name)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, sizeof(*name) * namelen);
+ void *res = REAL(asysctl)(name, namelen, len);
+ if (res && len) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, *len);
+ }
+ return res;
+}
+
+INTERCEPTOR(void *, asysctlbyname, const char *sname, SIZE_T *len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, asysctlbyname, sname, len);
+ if (sname)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1);
+ void *res = REAL(asysctlbyname)(sname, len);
+ if (res && len) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, *len);
+ }
+ return res;
+}
+#define INIT_ASYSCTL \
+ COMMON_INTERCEPT_FUNCTION(asysctl); \
+ COMMON_INTERCEPT_FUNCTION(asysctlbyname);
+#else
+#define INIT_ASYSCTL
+#endif
+
+#if SANITIZER_INTERCEPT_SYSCTLGETMIBINFO
+INTERCEPTOR(int, sysctlgetmibinfo, char *sname, int *name,
+ unsigned int *namelenp, char *cname, SIZE_T *csz, void **rnode,
+ int v) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sysctlgetmibinfo, sname, name, namelenp, cname,
+ csz, rnode, v);
+ if (sname)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1);
+ if (namelenp)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, namelenp, sizeof(*namelenp));
+ if (csz)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, csz, sizeof(*csz));
+ // Skip rnode, it's rarely used and not trivial to sanitize
+ // It's also used mostly internally
+ int res = REAL(sysctlgetmibinfo)(sname, name, namelenp, cname, csz, rnode, v);
+ if (!res) {
+ if (namelenp) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelenp, sizeof(*namelenp));
+ if (name)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, *namelenp * sizeof(*name));
+ }
+ if (csz) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, csz, sizeof(*csz));
+ if (cname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cname, *csz);
+ }
+ }
+ return res;
+}
+#define INIT_SYSCTLGETMIBINFO \
+ COMMON_INTERCEPT_FUNCTION(sysctlgetmibinfo);
+#else
+#define INIT_SYSCTLGETMIBINFO
+#endif
+
+#if SANITIZER_INTERCEPT_NL_LANGINFO
+INTERCEPTOR(char *, nl_langinfo, long item) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, nl_langinfo, item);
+ char *ret = REAL(nl_langinfo)(item);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, REAL(strlen)(ret) + 1);
+ return ret;
+}
+#define INIT_NL_LANGINFO COMMON_INTERCEPT_FUNCTION(nl_langinfo)
+#else
+#define INIT_NL_LANGINFO
+#endif
+
+#if SANITIZER_INTERCEPT_MODCTL
+INTERCEPTOR(int, modctl, int operation, void *argp) {
+ void *ctx;
+ int ret;
+ COMMON_INTERCEPTOR_ENTER(ctx, modctl, operation, argp);
+
+ if (operation == modctl_load) {
+ if (argp) {
+ __sanitizer_modctl_load_t *ml = (__sanitizer_modctl_load_t *)argp;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, ml, sizeof(*ml));
+ if (ml->ml_filename)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, ml->ml_filename,
+ REAL(strlen)(ml->ml_filename) + 1);
+ if (ml->ml_props)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, ml->ml_props, ml->ml_propslen);
+ }
+ ret = REAL(modctl)(operation, argp);
+ } else if (operation == modctl_unload) {
+ if (argp) {
+ const char *name = (const char *)argp;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ }
+ ret = REAL(modctl)(operation, argp);
+ } else if (operation == modctl_stat) {
+ uptr iov_len;
+ struct __sanitizer_iovec *iov = (struct __sanitizer_iovec *)argp;
+ if (iov) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, iov, sizeof(*iov));
+ iov_len = iov->iov_len;
+ }
+ ret = REAL(modctl)(operation, argp);
+ if (iov)
+ COMMON_INTERCEPTOR_WRITE_RANGE(
+ ctx, iov->iov_base, Min(iov_len, iov->iov_len));
+ } else if (operation == modctl_exists)
+ ret = REAL(modctl)(operation, argp);
+ else
+ ret = REAL(modctl)(operation, argp);
+
+ return ret;
+}
+#define INIT_MODCTL COMMON_INTERCEPT_FUNCTION(modctl)
+#else
+#define INIT_MODCTL
+#endif
+
+#if SANITIZER_INTERCEPT_STRTONUM
+INTERCEPTOR(long long, strtonum, const char *nptr, long long minval,
+ long long maxval, const char **errstr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strtonum, nptr, minval, maxval, errstr);
+
+ // TODO(kamil): Implement strtoll as a common inteceptor
+ char *real_endptr;
+ long long ret = (long long)REAL(strtoimax)(nptr, &real_endptr, 10);
+ StrtolFixAndCheck(ctx, nptr, nullptr, real_endptr, 10);
+
+ ret = REAL(strtonum)(nptr, minval, maxval, errstr);
+ if (errstr) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, errstr, sizeof(const char *));
+ if (*errstr)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *errstr, REAL(strlen)(*errstr) + 1);
+ }
+ return ret;
+}
+#define INIT_STRTONUM COMMON_INTERCEPT_FUNCTION(strtonum)
+#else
+#define INIT_STRTONUM
+#endif
+
+#if SANITIZER_INTERCEPT_FPARSELN
+INTERCEPTOR(char *, fparseln, __sanitizer_FILE *stream, SIZE_T *len,
+ SIZE_T *lineno, const char delim[3], int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fparseln, stream, len, lineno, delim, flags);
+ if (lineno)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, lineno, sizeof(*lineno));
+ if (delim)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, delim, sizeof(delim[0]) * 3);
+ char *ret = REAL(fparseln)(stream, len, lineno, delim, flags);
+ if (ret) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, REAL(strlen)(ret) + 1);
+ if (len)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len));
+ if (lineno)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineno, sizeof(*lineno));
+ }
+ return ret;
+}
+#define INIT_FPARSELN COMMON_INTERCEPT_FUNCTION(fparseln)
+#else
+#define INIT_FPARSELN
+#endif
+
+#if SANITIZER_INTERCEPT_STATVFS1
+INTERCEPTOR(int, statvfs1, const char *path, void *buf, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statvfs1, path, buf, flags);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ int res = REAL(statvfs1)(path, buf, flags);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatvfs1, int fd, void *buf, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs1, fd, buf, flags);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ int res = REAL(fstatvfs1)(fd, buf, flags);
+ if (!res) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ if (fd >= 0)
+ COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ }
+ return res;
+}
+#define INIT_STATVFS1 \
+ COMMON_INTERCEPT_FUNCTION(statvfs1); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs1);
+#else
+#define INIT_STATVFS1
+#endif
+
+#if SANITIZER_INTERCEPT_STRTOI
+INTERCEPTOR(INTMAX_T, strtoi, const char *nptr, char **endptr, int base,
+ INTMAX_T low, INTMAX_T high, int *rstatus) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strtoi, nptr, endptr, base, low, high, rstatus);
+ char *real_endptr;
+ INTMAX_T ret = REAL(strtoi)(nptr, &real_endptr, base, low, high, rstatus);
+ StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
+ if (rstatus)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rstatus, sizeof(*rstatus));
+ return ret;
+}
+
+INTERCEPTOR(UINTMAX_T, strtou, const char *nptr, char **endptr, int base,
+ UINTMAX_T low, UINTMAX_T high, int *rstatus) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strtou, nptr, endptr, base, low, high, rstatus);
+ char *real_endptr;
+ UINTMAX_T ret = REAL(strtou)(nptr, &real_endptr, base, low, high, rstatus);
+ StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
+ if (rstatus)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rstatus, sizeof(*rstatus));
+ return ret;
+}
+#define INIT_STRTOI \
+ COMMON_INTERCEPT_FUNCTION(strtoi); \
+ COMMON_INTERCEPT_FUNCTION(strtou)
+#else
+#define INIT_STRTOI
+#endif
+
+#if SANITIZER_INTERCEPT_CAPSICUM
+#define CAP_RIGHTS_INIT_INTERCEPTOR(cap_rights_init, rights, ...) \
+ { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_init, rights, ##__VA_ARGS__); \
+ if (rights) \
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \
+ __sanitizer_cap_rights_t *ret = \
+ REAL(cap_rights_init)(rights, ##__VA_ARGS__); \
+ if (ret) \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); \
+ return ret; \
+ }
+
+#define CAP_RIGHTS_SET_INTERCEPTOR(cap_rights_set, rights, ...) \
+ { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_set, rights, ##__VA_ARGS__); \
+ if (rights) \
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \
+ __sanitizer_cap_rights_t *ret = \
+ REAL(cap_rights_set)(rights, ##__VA_ARGS__); \
+ if (ret) \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); \
+ return ret; \
+ }
+
+#define CAP_RIGHTS_CLEAR_INTERCEPTOR(cap_rights_clear, rights, ...) \
+ { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_clear, rights, ##__VA_ARGS__); \
+ if (rights) \
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \
+ __sanitizer_cap_rights_t *ret = \
+ REAL(cap_rights_clear)(rights, ##__VA_ARGS__); \
+ if (ret) \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret)); \
+ return ret; \
+ }
+
+#define CAP_RIGHTS_IS_SET_INTERCEPTOR(cap_rights_is_set, rights, ...) \
+ { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_is_set, rights, ##__VA_ARGS__); \
+ if (rights) \
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights)); \
+ return REAL(cap_rights_is_set)(rights, ##__VA_ARGS__); \
+ }
+
+INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_init,
+ __sanitizer_cap_rights_t *rights) {
+ CAP_RIGHTS_INIT_INTERCEPTOR(cap_rights_init, rights);
+}
+
+INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_set,
+ __sanitizer_cap_rights_t *rights) {
+ CAP_RIGHTS_SET_INTERCEPTOR(cap_rights_set, rights);
+}
+
+INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_clear,
+ __sanitizer_cap_rights_t *rights) {
+ CAP_RIGHTS_CLEAR_INTERCEPTOR(cap_rights_clear, rights);
+}
+
+INTERCEPTOR(bool, cap_rights_is_set,
+ __sanitizer_cap_rights_t *rights) {
+ CAP_RIGHTS_IS_SET_INTERCEPTOR(cap_rights_is_set, rights);
+}
+
+INTERCEPTOR(int, cap_rights_limit, int fd,
+ const __sanitizer_cap_rights_t *rights) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_limit, fd, rights);
+ if (rights)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights));
+
+ return REAL(cap_rights_limit)(fd, rights);
+}
+
+INTERCEPTOR(int, cap_rights_get, int fd, __sanitizer_cap_rights_t *rights) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_get, fd, rights);
+ int ret = REAL(cap_rights_get)(fd, rights);
+ if (!ret && rights)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rights, sizeof(*rights));
+
+ return ret;
+}
+
+INTERCEPTOR(bool, cap_rights_is_valid, const __sanitizer_cap_rights_t *rights) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_is_valid, rights);
+ if (rights)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights));
+
+ return REAL(cap_rights_is_valid(rights));
+}
+
+INTERCEPTOR(__sanitizer_cap_rights *, cap_rights_merge,
+ __sanitizer_cap_rights *dst, const __sanitizer_cap_rights *src) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_merge, dst, src);
+ if (src)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+
+ __sanitizer_cap_rights *ret = REAL(cap_rights_merge)(dst, src);
+ if (dst)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst));
+
+ return ret;
+}
+
+INTERCEPTOR(__sanitizer_cap_rights *, cap_rights_remove,
+ __sanitizer_cap_rights *dst, const __sanitizer_cap_rights *src) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_remove, dst, src);
+ if (src)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+
+ __sanitizer_cap_rights *ret = REAL(cap_rights_remove)(dst, src);
+ if (dst)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst));
+
+ return ret;
+}
+
+INTERCEPTOR(bool, cap_rights_contains, const __sanitizer_cap_rights *big,
+ const __sanitizer_cap_rights *little) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_contains, big, little);
+ if (little)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, little, sizeof(*little));
+ if (big)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, big, sizeof(*big));
+
+ return REAL(cap_rights_contains)(big, little);
+}
+
+INTERCEPTOR(int, cap_ioctls_limit, int fd, const uptr *cmds, SIZE_T ncmds) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_ioctls_limit, fd, cmds, ncmds);
+ if (cmds)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, cmds, sizeof(*cmds) * ncmds);
+
+ return REAL(cap_ioctls_limit)(fd, cmds, ncmds);
+}
+
+INTERCEPTOR(int, cap_ioctls_get, int fd, uptr *cmds, SIZE_T maxcmds) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, cap_ioctls_get, fd, cmds, maxcmds);
+ int ret = REAL(cap_ioctls_get)(fd, cmds, maxcmds);
+ if (!ret && cmds)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cmds, sizeof(*cmds) * maxcmds);
+
+ return ret;
+}
+#define INIT_CAPSICUM \
+ COMMON_INTERCEPT_FUNCTION(cap_rights_init); \
+ COMMON_INTERCEPT_FUNCTION(cap_rights_set); \
+ COMMON_INTERCEPT_FUNCTION(cap_rights_clear); \
+ COMMON_INTERCEPT_FUNCTION(cap_rights_is_set); \
+ COMMON_INTERCEPT_FUNCTION(cap_rights_get); \
+ COMMON_INTERCEPT_FUNCTION(cap_rights_limit); \
+ COMMON_INTERCEPT_FUNCTION(cap_rights_contains); \
+ COMMON_INTERCEPT_FUNCTION(cap_rights_remove); \
+ COMMON_INTERCEPT_FUNCTION(cap_rights_merge); \
+ COMMON_INTERCEPT_FUNCTION(cap_rights_is_valid); \
+ COMMON_INTERCEPT_FUNCTION(cap_ioctls_get); \
+ COMMON_INTERCEPT_FUNCTION(cap_ioctls_limit)
+#else
+#define INIT_CAPSICUM
+#endif
+
+#if SANITIZER_INTERCEPT_SHA1
+INTERCEPTOR(void, SHA1Init, void *context) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, SHA1Init, context);
+ REAL(SHA1Init)(context);
+ if (context)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA1_CTX_sz);
+}
+INTERCEPTOR(void, SHA1Update, void *context, const u8 *data, unsigned len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, SHA1Update, context, data, len);
+ if (data && len > 0)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz);
+ REAL(SHA1Update)(context, data, len);
+ if (context)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA1_CTX_sz);
+}
+INTERCEPTOR(void, SHA1Final, u8 digest[20], void *context) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, SHA1Final, digest, context);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz);
+ REAL(SHA1Final)(digest, context);
+ if (digest)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(u8) * 20);
+}
+INTERCEPTOR(void, SHA1Transform, u32 state[5], u8 buffer[64]) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, SHA1Transform, state, buffer);
+ if (state)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, state, sizeof(u32) * 5);
+ if (buffer)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, sizeof(u8) * 64);
+ REAL(SHA1Transform)(state, buffer);
+ if (state)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, state, sizeof(u32) * 5);
+}
+INTERCEPTOR(char *, SHA1End, void *context, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, SHA1End, context, buf);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz);
+ char *ret = REAL(SHA1End)(context, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length);
+ return ret;
+}
+INTERCEPTOR(char *, SHA1File, char *filename, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, SHA1File, filename, buf);
+ if (filename)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+ char *ret = REAL(SHA1File)(filename, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length);
+ return ret;
+}
+INTERCEPTOR(char *, SHA1FileChunk, char *filename, char *buf, OFF_T offset,
+ OFF_T length) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, SHA1FileChunk, filename, buf, offset, length);
+ if (filename)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+ char *ret = REAL(SHA1FileChunk)(filename, buf, offset, length);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length);
+ return ret;
+}
+INTERCEPTOR(char *, SHA1Data, u8 *data, SIZE_T len, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, SHA1Data, data, len, buf);
+ if (data)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+ char *ret = REAL(SHA1Data)(data, len, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length);
+ return ret;
+}
+#define INIT_SHA1 \
+ COMMON_INTERCEPT_FUNCTION(SHA1Init); \
+ COMMON_INTERCEPT_FUNCTION(SHA1Update); \
+ COMMON_INTERCEPT_FUNCTION(SHA1Final); \
+ COMMON_INTERCEPT_FUNCTION(SHA1Transform); \
+ COMMON_INTERCEPT_FUNCTION(SHA1End); \
+ COMMON_INTERCEPT_FUNCTION(SHA1File); \
+ COMMON_INTERCEPT_FUNCTION(SHA1FileChunk); \
+ COMMON_INTERCEPT_FUNCTION(SHA1Data)
+#else
+#define INIT_SHA1
+#endif
+
+#if SANITIZER_INTERCEPT_MD4
+INTERCEPTOR(void, MD4Init, void *context) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD4Init, context);
+ REAL(MD4Init)(context);
+ if (context)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD4_CTX_sz);
+}
+
+INTERCEPTOR(void, MD4Update, void *context, const unsigned char *data,
+ unsigned int len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD4Update, context, data, len);
+ if (data && len > 0)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz);
+ REAL(MD4Update)(context, data, len);
+ if (context)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD4_CTX_sz);
+}
+
+INTERCEPTOR(void, MD4Final, unsigned char digest[16], void *context) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD4Final, digest, context);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz);
+ REAL(MD4Final)(digest, context);
+ if (digest)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16);
+}
+
+INTERCEPTOR(char *, MD4End, void *context, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD4End, context, buf);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz);
+ char *ret = REAL(MD4End)(context, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length);
+ return ret;
+}
+
+INTERCEPTOR(char *, MD4File, const char *filename, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD4File, filename, buf);
+ if (filename)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+ char *ret = REAL(MD4File)(filename, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length);
+ return ret;
+}
+
+INTERCEPTOR(char *, MD4Data, const unsigned char *data, unsigned int len,
+ char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD4Data, data, len, buf);
+ if (data && len > 0)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+ char *ret = REAL(MD4Data)(data, len, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length);
+ return ret;
+}
+
+#define INIT_MD4 \
+ COMMON_INTERCEPT_FUNCTION(MD4Init); \
+ COMMON_INTERCEPT_FUNCTION(MD4Update); \
+ COMMON_INTERCEPT_FUNCTION(MD4Final); \
+ COMMON_INTERCEPT_FUNCTION(MD4End); \
+ COMMON_INTERCEPT_FUNCTION(MD4File); \
+ COMMON_INTERCEPT_FUNCTION(MD4Data)
+#else
+#define INIT_MD4
+#endif
+
+#if SANITIZER_INTERCEPT_RMD160
+INTERCEPTOR(void, RMD160Init, void *context) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, RMD160Init, context);
+ REAL(RMD160Init)(context);
+ if (context)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, RMD160_CTX_sz);
+}
+INTERCEPTOR(void, RMD160Update, void *context, const u8 *data, unsigned len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, RMD160Update, context, data, len);
+ if (data && len > 0)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz);
+ REAL(RMD160Update)(context, data, len);
+ if (context)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, RMD160_CTX_sz);
+}
+INTERCEPTOR(void, RMD160Final, u8 digest[20], void *context) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, RMD160Final, digest, context);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz);
+ REAL(RMD160Final)(digest, context);
+ if (digest)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(u8) * 20);
+}
+INTERCEPTOR(void, RMD160Transform, u32 state[5], u16 buffer[16]) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, RMD160Transform, state, buffer);
+ if (state)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, state, sizeof(u32) * 5);
+ if (buffer)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, sizeof(u32) * 16);
+ REAL(RMD160Transform)(state, buffer);
+ if (state)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, state, sizeof(u32) * 5);
+}
+INTERCEPTOR(char *, RMD160End, void *context, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, RMD160End, context, buf);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz);
+ char *ret = REAL(RMD160End)(context, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length);
+ return ret;
+}
+INTERCEPTOR(char *, RMD160File, char *filename, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, RMD160File, filename, buf);
+ if (filename)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+ char *ret = REAL(RMD160File)(filename, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length);
+ return ret;
+}
+INTERCEPTOR(char *, RMD160FileChunk, char *filename, char *buf, OFF_T offset,
+ OFF_T length) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, RMD160FileChunk, filename, buf, offset, length);
+ if (filename)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+ char *ret = REAL(RMD160FileChunk)(filename, buf, offset, length);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length);
+ return ret;
+}
+INTERCEPTOR(char *, RMD160Data, u8 *data, SIZE_T len, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, RMD160Data, data, len, buf);
+ if (data && len > 0)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+ char *ret = REAL(RMD160Data)(data, len, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length);
+ return ret;
+}
+#define INIT_RMD160 \
+ COMMON_INTERCEPT_FUNCTION(RMD160Init); \
+ COMMON_INTERCEPT_FUNCTION(RMD160Update); \
+ COMMON_INTERCEPT_FUNCTION(RMD160Final); \
+ COMMON_INTERCEPT_FUNCTION(RMD160Transform); \
+ COMMON_INTERCEPT_FUNCTION(RMD160End); \
+ COMMON_INTERCEPT_FUNCTION(RMD160File); \
+ COMMON_INTERCEPT_FUNCTION(RMD160FileChunk); \
+ COMMON_INTERCEPT_FUNCTION(RMD160Data)
+#else
+#define INIT_RMD160
+#endif
+
+#if SANITIZER_INTERCEPT_MD5
+INTERCEPTOR(void, MD5Init, void *context) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD5Init, context);
+ REAL(MD5Init)(context);
+ if (context)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD5_CTX_sz);
+}
+
+INTERCEPTOR(void, MD5Update, void *context, const unsigned char *data,
+ unsigned int len) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD5Update, context, data, len);
+ if (data && len > 0)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz);
+ REAL(MD5Update)(context, data, len);
+ if (context)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD5_CTX_sz);
+}
+
+INTERCEPTOR(void, MD5Final, unsigned char digest[16], void *context) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD5Final, digest, context);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz);
+ REAL(MD5Final)(digest, context);
+ if (digest)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16);
+}
+
+INTERCEPTOR(char *, MD5End, void *context, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD5End, context, buf);
+ if (context)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz);
+ char *ret = REAL(MD5End)(context, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length);
+ return ret;
+}
+
+INTERCEPTOR(char *, MD5File, const char *filename, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD5File, filename, buf);
+ if (filename)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+ char *ret = REAL(MD5File)(filename, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length);
+ return ret;
+}
+
+INTERCEPTOR(char *, MD5Data, const unsigned char *data, unsigned int len,
+ char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, MD5Data, data, len, buf);
+ if (data && len > 0)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+ char *ret = REAL(MD5Data)(data, len, buf);
+ if (ret)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length);
+ return ret;
+}
+
+#define INIT_MD5 \
+ COMMON_INTERCEPT_FUNCTION(MD5Init); \
+ COMMON_INTERCEPT_FUNCTION(MD5Update); \
+ COMMON_INTERCEPT_FUNCTION(MD5Final); \
+ COMMON_INTERCEPT_FUNCTION(MD5End); \
+ COMMON_INTERCEPT_FUNCTION(MD5File); \
+ COMMON_INTERCEPT_FUNCTION(MD5Data)